ソースを参照

Adds explore repo from here command (wip)

Replaces git content provider with git fs provider
Adds Buffer output support to git calls
main
Eric Amodio 6年前
コミット
4320f5342c
22個のファイルの変更735行の追加361行の削除
  1. +172
    -128
      package-lock.json
  2. +15
    -3
      package.json
  3. +1
    -1
      src/codelens/gitCodeLensProvider.ts
  4. +13
    -7
      src/commands/common.ts
  5. +2
    -1
      src/constants.ts
  6. +3
    -5
      src/container.ts
  7. +172
    -0
      src/git/fsProvider.ts
  8. +115
    -91
      src/git/git.ts
  9. +3
    -3
      src/git/gitLocator.ts
  10. +37
    -20
      src/git/gitUri.ts
  11. +1
    -0
      src/git/models/models.ts
  12. +1
    -1
      src/git/models/repository.ts
  13. +8
    -0
      src/git/models/tree.ts
  14. +1
    -0
      src/git/parsers/parsers.ts
  15. +32
    -0
      src/git/parsers/treeParser.ts
  16. +1
    -1
      src/git/remotes/provider.ts
  17. +11
    -6
      src/git/shell.ts
  18. +0
    -32
      src/gitContentProvider.ts
  19. +47
    -27
      src/gitService.ts
  20. +48
    -22
      src/system/searchTree.ts
  21. +37
    -12
      src/system/string.ts
  22. +15
    -1
      src/views/explorerCommands.ts

+ 172
- 128
package-lock.json ファイルの表示

@ -15,9 +15,9 @@
}
},
"@nodelib/fs.stat": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.1.tgz",
"integrity": "sha512-KU/VDjC5RwtDUZiz3d+DHXJF2lp5hB9dn552TXIyptj8SH1vXmR40mG0JgGq03IlYsOgGfcv8xrLpSQ0YUMQdA==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.2.tgz",
"integrity": "sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw==",
"dev": true
},
"@types/clipboardy": {
@ -32,12 +32,6 @@
"integrity": "sha512-zbteaWZ2mdduacm0byELwtRyhYE40aK+pAanQk415gr1eRuu67x7QGOLmn8jz5zI8LDK7d0WI/oT6r5Trz4rzQ==",
"dev": true
},
"@types/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=",
"dev": true
},
"@webassemblyjs/ast": {
"version": "1.5.13",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.13.tgz",
@ -1062,7 +1056,7 @@
},
"buffer": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz",
"integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=",
"dev": true,
"requires": {
@ -1266,9 +1260,9 @@
}
},
"capture-stack-trace": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
"integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
"integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==",
"dev": true
},
"caseless": {
@ -1299,7 +1293,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@ -1311,9 +1305,9 @@
}
},
"chardet": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.5.0.tgz",
"integrity": "sha512-9ZTaoBaePSCFvNlNGrsyI8ZVACP2svUtq0DkM7t4K2ClAa96sqOIRjAzDTc8zXzFt1cZR46rRzLTiHFSJ+Qw0g==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
"chokidar": {
@ -1364,9 +1358,9 @@
}
},
"ci-info": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.4.0.tgz",
"integrity": "sha512-Oqmw2pVfCl8sCL+1QgMywPfdxPJPkC51y4usw0iiE2S9qnEOAqXy8bwl1CpMpnoU39g4iKJTz6QZj+28FvOnjQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.5.0.tgz",
"integrity": "sha512-Bx/xWOzip4whERIvC97aIHjWCa8FxEn0ezng0oVn4kma6p+90Fbs3bTcJw6ZL0da2EPHydxsXJPZxNUv5oWb1Q==",
"dev": true
},
"cipher-base": {
@ -1571,18 +1565,18 @@
}
},
"color-convert": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
"integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.1"
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"color-support": {
@ -1718,10 +1712,13 @@
"dev": true
},
"convert-source-map": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
"dev": true
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.1"
}
},
"copy-concurrently": {
"version": "1.0.5",
@ -1934,6 +1931,12 @@
"source-map": "^0.5.3"
}
},
"mdn-data": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz",
"integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@ -2688,18 +2691,18 @@
"dev": true
},
"event-stream": {
"version": "3.3.4",
"resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
"integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz",
"integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==",
"dev": true,
"requires": {
"duplexer": "~0.1.1",
"from": "~0",
"map-stream": "~0.1.0",
"pause-stream": "0.0.11",
"split": "0.3",
"stream-combiner": "~0.0.4",
"through": "~2.3.1"
"duplexer": "^0.1.1",
"from": "^0.1.7",
"map-stream": "0.0.7",
"pause-stream": "^0.0.11",
"split": "^1.0.1",
"stream-combiner": "^0.2.2",
"through": "^2.3.8"
}
},
"events": {
@ -2920,13 +2923,13 @@
}
},
"external-editor": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.1.tgz",
"integrity": "sha512-e1neqvSt5pSwQcFnYc6yfGuJD2Q4336cdbHs5VeUO0zTkqPbrHMyw2q1r47fpfLWbvIG8H8A6YO3sck7upTV6Q==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
"integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
"dev": true,
"requires": {
"chardet": "^0.5.0",
"iconv-lite": "^0.4.22",
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
}
},
@ -3934,9 +3937,9 @@
}
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@ -4182,7 +4185,7 @@
},
"got": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz",
"resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz",
"integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
"dev": true,
"requires": {
@ -5011,7 +5014,7 @@
},
"html-webpack-plugin": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
"resolved": "http://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
"integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=",
"dev": true,
"requires": {
@ -5833,9 +5836,9 @@
}
},
"js-base64": {
"version": "2.4.8",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz",
"integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q==",
"version": "2.4.9",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz",
"integrity": "sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ==",
"dev": true
},
"js-tokens": {
@ -6299,6 +6302,15 @@
"integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==",
"dev": true
},
"map-age-cleaner": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz",
"integrity": "sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ==",
"dev": true,
"requires": {
"p-defer": "^1.0.0"
}
},
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@ -6312,9 +6324,9 @@
"dev": true
},
"map-stream": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
"integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=",
"dev": true
},
"map-visit": {
@ -6343,9 +6355,9 @@
}
},
"mdn-data": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz",
"integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.2.0.tgz",
"integrity": "sha512-esDqNvsJB2q5V28+u7NdtdMg6Rmg4khQmAVSjUiX7BY/7haIv0K2yWM43hYp0or+3nvG7+UaTF1JHz31hgU1TA==",
"dev": true
},
"mem": {
@ -6556,7 +6568,7 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
@ -6661,7 +6673,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
@ -6670,7 +6682,7 @@
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}
@ -6715,6 +6727,20 @@
"integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
"dev": true
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
@ -6915,7 +6941,7 @@
},
"buffer": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true,
"requires": {
@ -7275,7 +7301,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true,
"requires": {
@ -7285,7 +7311,8 @@
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
"osenv": {
"version": "0.1.5",
@ -7303,6 +7330,12 @@
"integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==",
"dev": true
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"dev": true
},
"p-event": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz",
@ -7317,6 +7350,12 @@
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-is-promise": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
"dev": true
},
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
@ -8217,7 +8256,7 @@
},
"yargs": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
"dev": true,
"requires": {
@ -8860,9 +8899,9 @@
}
},
"rxjs": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
"integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.2.tgz",
"integrity": "sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
@ -8963,7 +9002,7 @@
"dependencies": {
"commander": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"dev": true,
"requires": {
@ -9344,15 +9383,15 @@
}
},
"spdx-license-ids": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
"integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz",
"integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==",
"dev": true
},
"split": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
"integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
"dev": true,
"requires": {
"through": "2"
@ -9527,12 +9566,13 @@
}
},
"stream-combiner": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
"integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
"integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=",
"dev": true,
"requires": {
"duplexer": "~0.1.1"
"duplexer": "~0.1.1",
"through": "~2.3.4"
}
},
"stream-combiner2": {
@ -10016,6 +10056,7 @@
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
}
@ -10301,9 +10342,9 @@
"dev": true
},
"uglify-js": {
"version": "3.4.8",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.8.tgz",
"integrity": "sha512-WatYTD84gP/867bELqI2F/2xC9PQBETn/L+7RGq9MQOA/7yFBNvY1UwXqvtILeE6n0ITwBXxp34M0/o70dzj6A==",
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
"dev": true,
"requires": {
"commander": "~2.17.1",
@ -10929,16 +10970,6 @@
"ajv": "^6.1.0",
"ajv-keywords": "^3.1.0"
}
},
"webpack-sources": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.2.0.tgz",
"integrity": "sha512-9BZwxR85dNsjWz3blyxdOhTgtnQvv3OEs5xofI0wPYTwu5kaWxS08UuD1oI7WLBLpRO+ylf0ofnXLXWmGb2WMw==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
}
}
}
},
@ -11027,31 +11058,18 @@
}
},
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
"integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz",
"integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==",
"dev": true,
"requires": {
"cross-spawn": "^5.0.1",
"cross-spawn": "^6.0.0",
"get-stream": "^3.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
},
"dependencies": {
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"dev": true,
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
}
}
},
"find-up": {
@ -11063,12 +11081,27 @@
"locate-path": "^3.0.0"
}
},
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
"invert-kv": "^2.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@ -11079,15 +11112,26 @@
"path-exists": "^3.0.0"
}
},
"mem": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz",
"integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==",
"dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^1.0.0",
"p-is-promise": "^1.1.0"
}
},
"os-locale": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
"integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz",
"integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==",
"dev": true,
"requires": {
"execa": "^0.7.0",
"lcid": "^1.0.0",
"mem": "^1.1.0"
"execa": "^0.10.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"p-limit": {
@ -11155,16 +11199,16 @@
"dev": true
},
"yargs": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.1.tgz",
"integrity": "sha512-B0vRAp1hRX4jgIOWFtjfNjd9OA9RWYZ6tqGA9/I/IrTMsxmKvtWy+ersM+jzpQqbC3YfLzeABPdeTgcJ9eu1qQ==",
"version": "12.0.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz",
"integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==",
"dev": true,
"requires": {
"cliui": "^4.0.0",
"decamelize": "^2.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^1.0.1",
"os-locale": "^2.0.0",
"os-locale": "^3.0.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
@ -11186,9 +11230,9 @@
}
},
"webpack-deep-scope-analysis": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/webpack-deep-scope-analysis/-/webpack-deep-scope-analysis-1.5.2.tgz",
"integrity": "sha512-10Gna02usg2HSfx14MsTj+OojaenSewMSVjdTNFUndEE7yCKjEiIAH1N9V+bV1oypIvhTqmfKQToR2y6ppOclA==",
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/webpack-deep-scope-analysis/-/webpack-deep-scope-analysis-1.5.4.tgz",
"integrity": "sha512-jnj1XNSO3eNBVZFhyHLFTD4sAxAtWMum0bdLF3UkMWSgVD2AhZMoXzfP2u4QSt2obaFDmTBMar5bIBnDpk+ZzA==",
"dev": true,
"requires": {
"esrecurse": "^4.2.1",
@ -11211,9 +11255,9 @@
"dev": true
},
"webpack-sources": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz",
"integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.2.0.tgz",
"integrity": "sha512-9BZwxR85dNsjWz3blyxdOhTgtnQvv3OEs5xofI0wPYTwu5kaWxS08UuD1oI7WLBLpRO+ylf0ofnXLXWmGb2WMw==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
@ -11254,7 +11298,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true,
"requires": {

+ 15
- 3
package.json ファイルの表示

@ -1801,6 +1801,11 @@
"category": "GitLens"
},
{
"command": "gitlens.explorers.exploreRepoRevision",
"title": "Explore the Repository from Here",
"category": "GitLens"
},
{
"command": "gitlens.explorers.openDirectoryDiff",
"title": "Open Directory Compare",
"category": "GitLens"
@ -2383,6 +2388,10 @@
"when": "gitlens:enabled"
},
{
"command": "gitlens.explorers.exploreRepoRevision",
"when": "false"
},
{
"command": "gitlens.explorers.openChanges",
"when": "false"
},
@ -3031,7 +3040,7 @@
{
"command": "gitlens.explorers.openDirectoryDiffWithWorking",
"when": "viewItem =~ /gitlens:(branch|tag)\\b/",
"group": "7_gitlens_diff@1"
"group": "7_gitlens_more@2"
},
{
"command": "gitlens.explorers.terminalCheckoutBranch",
@ -3239,6 +3248,11 @@
"group": "8_gitlens@1"
},
{
"command": "gitlens.explorers.exploreRepoRevision",
"when": "viewItem =~ /gitlens:(branch|commit|file:(commit|status)|stash|tag)\\b/",
"group": "7_gitlens_more@1"
},
{
"command": "gitlens.openRepoInRemote",
"when": "viewItem == gitlens:repository && gitlens:hasRemotes",
"group": "1_gitlens@1"
@ -3582,13 +3596,11 @@
"iconv-lite": "0.4.24",
"lodash.debounce": "4.0.8",
"lodash.once": "4.1.1",
"tmp": "0.0.33",
"tslib": "1.9.3"
},
"devDependencies": {
"@types/clipboardy": "1.1.0",
"@types/node": "8.10.29",
"@types/tmp": "0.0.33",
"clean-webpack-plugin": "0.1.19",
"css-loader": "1.0.0",
"html-webpack-inline-source-plugin": "0.0.10",

+ 1
- 1
src/codelens/gitCodeLensProvider.ts ファイルの表示

@ -86,7 +86,7 @@ export class GitCodeLensProvider implements CodeLensProvider {
static selector: DocumentSelector = [
{ scheme: DocumentSchemes.File },
{ scheme: DocumentSchemes.Git },
{ scheme: DocumentSchemes.GitLensGit }
{ scheme: DocumentSchemes.GitLens }
];
constructor(

+ 13
- 7
src/commands/common.ts ファイルの表示

@ -397,13 +397,8 @@ export async function openEditor(
uri = uri.documentUri({ noSha: true });
}
// This is a bit of an ugly hack, but I added it because there a bunch of call sites and toRevisionUri can't be easily made async because of its use in ctors
if (uri.scheme === DocumentSchemes.GitLensGit && ImageMimetypes[path.extname(uri.fsPath)]) {
const gitUri = GitUri.fromRevisionUri(uri);
const imageUri = await Container.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha);
if (imageUri !== undefined) {
await commands.executeCommand(BuiltInCommands.Open, imageUri);
}
if (uri.scheme === DocumentSchemes.GitLens && ImageMimetypes[path.extname(uri.fsPath)]) {
await commands.executeCommand(BuiltInCommands.Open, uri);
return undefined;
}
@ -430,3 +425,14 @@ export async function openEditor(
return undefined;
}
}
export function openWorkspace(uri: Uri, name: string, options: { openInNewWindow?: boolean } = {}) {
if (options.openInNewWindow) {
commands.executeCommand(BuiltInCommands.OpenFolder, uri, true);
return true;
}
const count = (workspace.workspaceFolders && workspace.workspaceFolders.length) || 0;
return workspace.updateWorkspaceFolders(count, 0, { uri, name });
}

+ 2
- 1
src/constants.ts ファイルの表示

@ -16,6 +16,7 @@ export enum BuiltInCommands {
ExecuteDocumentSymbolProvider = 'vscode.executeDocumentSymbolProvider',
ExecuteCodeLensProvider = 'vscode.executeCodeLensProvider',
Open = 'vscode.open',
OpenFolder = 'vscode.openFolder',
NextEditor = 'workbench.action.nextEditor',
PreviewHtml = 'vscode.previewHtml',
RevealLine = 'revealLine',
@ -48,7 +49,7 @@ export enum DocumentSchemes {
DebugConsole = 'debug',
File = 'file',
Git = 'git',
GitLensGit = 'gitlens-git',
GitLens = 'gitlens',
Output = 'output'
}

+ 3
- 5
src/container.ts ファイルの表示

@ -1,10 +1,10 @@
'use strict';
import { Disposable, ExtensionContext, languages, workspace } from 'vscode';
import { Disposable, ExtensionContext } from 'vscode';
import { FileAnnotationController } from './annotations/fileAnnotationController';
import { LineAnnotationController } from './annotations/lineAnnotationController';
import { CodeLensController } from './codelens/codeLensController';
import { configuration, IConfig } from './configuration';
import { GitContentProvider } from './gitContentProvider';
import { GitFileSystemProvider } from './git/fsProvider';
import { GitService } from './gitService';
import { LineHoverController } from './hovers/lineHoverController';
import { Keyboard } from './keyboard';
@ -65,9 +65,7 @@ export class Container {
});
}
context.subscriptions.push(
workspace.registerTextDocumentContentProvider(GitContentProvider.scheme, new GitContentProvider())
);
context.subscriptions.push(new GitFileSystemProvider());
}
private static _codeLensController: CodeLensController;

+ 172
- 0
src/git/fsProvider.ts ファイルの表示

@ -0,0 +1,172 @@
'use strict';
import {
Disposable,
Event,
EventEmitter,
FileChangeEvent,
FileStat,
FileSystemError,
FileSystemProvider,
FileType,
Uri,
workspace
} from 'vscode';
import { DocumentSchemes } from '../constants';
import { Container } from '../container';
import { GitService, GitTree, GitUri } from '../gitService';
import { Iterables, TernarySearchTree } from '../system';
export function fromGitLensFSUri(uri: Uri): { path: string; ref: string; repoPath: string } {
const gitUri = uri instanceof GitUri ? uri : GitUri.fromRevisionUri(uri);
return { path: gitUri.getRelativePath(), ref: gitUri.sha!, repoPath: gitUri.repoPath! };
}
export function toGitLensFSUri(ref: string, repoPath: string): Uri {
return GitUri.toRevisionUri(ref, repoPath, repoPath);
}
const emptyArray = new Uint8Array(0);
export class GitFileSystemProvider implements FileSystemProvider, Disposable {
private readonly _disposable: Disposable;
private readonly _searchTreeMap = new Map<string, Promise<TernarySearchTree<GitTree>>>();
constructor() {
this._disposable = Disposable.from(
workspace.registerFileSystemProvider(DocumentSchemes.GitLens, this, {
isCaseSensitive: true,
isReadonly: true
})
);
}
dispose() {
this._disposable && this._disposable.dispose();
}
private _onDidChangeFile = new EventEmitter<FileChangeEvent[]>();
get onDidChangeFile(): Event<FileChangeEvent[]> {
return this._onDidChangeFile.event;
}
copy?(): void | Thenable<void> {
throw FileSystemError.NoPermissions;
}
createDirectory(): void | Thenable<void> {
throw FileSystemError.NoPermissions;
}
delete(): void | Thenable<void> {
throw FileSystemError.NoPermissions;
}
async readDirectory(uri: Uri): Promise<[string, FileType][]> {
const tree = await this.getTree(uri);
if (tree === undefined) {
debugger;
throw FileSystemError.FileNotFound(uri);
}
const items = [...Iterables.map<GitTree, [string, FileType]>(tree, t => [t.path, typeToFileType(t.type)])];
return items;
}
async readFile(uri: Uri): Promise<Uint8Array> {
const { path, ref, repoPath } = fromGitLensFSUri(uri);
if (ref === GitService.deletedSha) return emptyArray;
const buffer = await Container.git.getVersionedFileBuffer(repoPath, path, ref);
if (buffer === undefined) return emptyArray;
return buffer;
}
rename(): void | Thenable<void> {
throw FileSystemError.NoPermissions;
}
async stat(uri: Uri): Promise<FileStat> {
const { path, ref, repoPath } = fromGitLensFSUri(uri);
if (ref === GitService.deletedSha) {
return {
type: FileType.File,
size: 0,
ctime: 0,
mtime: 0
};
}
let treeItem;
const searchTree = this._searchTreeMap.get(ref);
if (searchTree !== undefined) {
// Add the fake root folder to the path
treeItem = (await searchTree).get(`/~/${path}`);
}
else {
treeItem = await Container.git.getTreeFileForRevision(repoPath, path, ref);
}
if (treeItem === undefined) {
throw FileSystemError.FileNotFound(uri);
}
return {
type: typeToFileType(treeItem.type),
size: treeItem.size,
ctime: 0,
mtime: 0
};
}
watch(): Disposable {
return { dispose: () => {} };
}
writeFile(): void | Thenable<void> {
throw FileSystemError.NoPermissions;
}
private async createSearchTree(ref: string, repoPath: string) {
const searchTree = TernarySearchTree.forPaths() as TernarySearchTree<GitTree>;
const trees = await Container.git.getTreeForRevision(repoPath, ref);
// Add a fake root folder so that searches will work
searchTree.set(`~`, { commitSha: '', path: '~', size: 0, type: 'tree' });
for (const item of trees) {
searchTree.set(`~/${item.path}`, item);
}
return searchTree;
}
private async getOrCreateSearchTree(ref: string, repoPath: string) {
let searchTree = this._searchTreeMap.get(ref);
if (searchTree === undefined) {
searchTree = this.createSearchTree(ref, repoPath);
this._searchTreeMap.set(ref, searchTree);
}
return searchTree;
}
private async getTree(uri: Uri) {
const { path, ref, repoPath } = fromGitLensFSUri(uri);
const searchTree = await this.getOrCreateSearchTree(ref, repoPath);
// Add the fake root folder to the path
return searchTree!.findSuperstr(`/~/${path}`, true);
}
}
function typeToFileType(type: 'blob' | 'tree' | undefined | null) {
switch (type) {
case 'blob':
return FileType.File;
case 'tree':
return FileType.Directory;
default:
return FileType.Unknown;
}
}

+ 115
- 91
src/git/git.ts ファイルの表示

@ -1,5 +1,4 @@
'use strict';
import * as fs from 'fs';
import * as iconv from 'iconv-lite';
import * as path from 'path';
import { GlyphChars } from '../constants';
@ -71,9 +70,9 @@ interface GitCommandOptions extends RunOptions {
}
// A map of running git commands -- avoids running duplicate overlaping commands
const pendingCommands: Map<string, Promise<string>> = new Map();
const pendingCommands: Map<string, Promise<string | Buffer>> = new Map();
async function git(options: GitCommandOptions, ...args: any[]): Promise<string> {
async function git<TOut extends string | Buffer>(options: GitCommandOptions, ...args: any[]): Promise<TOut> {
const start = process.hrtime();
const { correlationKey, exceptionHandler, ...opts } = options;
@ -81,7 +80,7 @@ async function git(options: GitCommandOptions, ...args: any[]): Promise
const encoding = options.encoding || 'utf8';
const runOpts = {
...opts,
encoding: encoding === 'utf8' ? 'utf8' : 'binary',
encoding: encoding === 'utf8' ? 'utf8' : encoding === 'buffer' ? 'buffer' : 'binary',
// Adds GCM environment variables to avoid any possible credential issues -- from https://github.com/Microsoft/vscode/issues/26573#issuecomment-338686581
// Shouldn't *really* be needed but better safe than sorry
env: { ...(options.env || process.env), GCM_INTERACTIVE: 'NEVER', GCM_PRESERVE_CREDS: 'TRUE', LC_ALL: 'C' }
@ -99,7 +98,7 @@ async function git(options: GitCommandOptions, ...args: any[]): Promise
// See https://stackoverflow.com/questions/4144417/how-to-handle-asian-characters-in-file-names-in-git-on-os-x
args.splice(0, 0, '-c', 'core.quotepath=false', '-c', 'color.ui=false');
promise = run(gitInfo.path, args, encoding, runOpts);
promise = run<TOut>(gitInfo.path, args, encoding, runOpts);
pendingCommands.set(command, promise);
}
@ -109,19 +108,19 @@ async function git(options: GitCommandOptions, ...args: any[]): Promise
let exception: Error | undefined;
try {
return await promise;
return (await promise) as TOut;
}
catch (ex) {
exception = ex;
if (exceptionHandler !== undefined) {
const result = exceptionHandler(ex);
exception = undefined;
return result;
return result as TOut;
}
const result = defaultExceptionHandler(ex, options, ...args);
exception = undefined;
return result;
return result as TOut;
}
finally {
pendingCommands.delete(command);
@ -196,47 +195,47 @@ export class Git {
);
}
static async getVersionedFile(repoPath: string | undefined, fileName: string, ref: string) {
const data = await Git.show(repoPath, fileName, ref, { encoding: 'binary' });
if (data === undefined) return undefined;
if (Git.isStagedUncommitted(ref)) {
ref = '';
}
const suffix = Strings.truncate(
Strings.sanitizeForFileSystem(Git.isSha(ref) ? Git.shortenSha(ref)! : ref),
50,
''
);
const ext = path.extname(fileName);
const tmp = await import('tmp');
return new Promise<string>((resolve, reject) => {
tmp.file(
{ prefix: `${path.basename(fileName, ext)}-${suffix}__`, postfix: ext },
(err, destination, fd, cleanupCallback) => {
if (err) {
reject(err);
return;
}
Logger.log(`getVersionedFile[${destination}]('${repoPath}', '${fileName}', ${ref})`);
fs.appendFile(destination, data, { encoding: 'binary' }, err => {
if (err) {
reject(err);
return;
}
class="kr">const ReadOnly ="o">= 0o100444; // 33060 0b1000000100100100
fs.chmod(destination, ReadOnly, err => {
resolve(destination);
class="p">});
class="p">});
}
);
});
}
// static async getVersionedFile(repoPath: string | undefined, fileName: string, ref: string) {
// const buffer = await Git.show<Buffer>(repoPath, fileName, ref, { encoding: 'buffer' });
// if (buffer === undefined) return undefined;
// if (Git.isStagedUncommitted(ref)) {
// ref = '';
// }
// const suffix = Strings.truncate(
// Strings.sanitizeForFileSystem(Git.isSha(ref) ? Git.shortenSha(ref)! : ref),
// 50,
// ''
// );
// const ext = path.extname(fileName);
// const tmp = await import('tmp');
// return new Promise<string>((resolve, reject) => {
// tmp.file(
// { prefix: `${path.basename(fileName, ext)}-${suffix}__`, postfix: ext },
// (err, destination, fd, cleanupCallback) => {
// if (err) {
// reject(err);
// return;
// }
// Logger.log(`getVersionedFile[${destination}]('${repoPath}', '${fileName}', ${ref})`);
// fs.appendFile(destination, buffer, { encoding: 'binary' }, err => {
// if (err) {
// reject(err);
// return;
// }
// const ReadOnly = 0o100444; // 33060 0b1000000100100100
// fs.chmod(destination, ReadOnly, err => {
// resolve(destination);
// });
// });
// }
// );
// });
// }
static isResolveRequired(sha: string) {
return Git.isSha(sha) && !Git.shaStrictRegex.test(sha);
@ -325,14 +324,14 @@ export class Git {
params.push('--contents', '-');
// Get the file contents for the staged version using `:`
stdin = await Git.show(repoPath, fileName, ':');
stdin = await Git.show<string>(repoPath, fileName, ':');
}
else {
params.push(sha);
}
}
return git({ cwd: root, stdin: stdin }, ...params, '--', file);
return git<string>({ cwd: root, stdin: stdin }, ...params, '--', file);
}
static async blame_contents(
@ -364,7 +363,12 @@ export class Git {
// Pipe the blame contents to stdin
params.push('--contents', '-');
return git({ cwd: root, stdin: contents, correlationKey: options.correlationKey }, ...params, '--', file);
return git<string>(
{ cwd: root, stdin: contents, correlationKey: options.correlationKey },
...params,
'--',
file
);
}
static branch(repoPath: string, options: { all: boolean } = { all: false }) {
@ -373,7 +377,7 @@ export class Git {
params.push('-a');
}
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static branch_contains(repoPath: string, ref: string, options: { remote: boolean } = { remote: false }) {
@ -382,21 +386,21 @@ export class Git {
params.push('-r');
}
return git({ cwd: repoPath }, ...params, ref);
return git<string>({ cwd: repoPath }, ...params, ref);
}
static check_mailmap(repoPath: string, author: string) {
return git({ cwd: repoPath }, 'check-mailmap', author);
return git<string>({ cwd: repoPath }, 'check-mailmap', author);
}
static checkout(repoPath: string, fileName: string, sha: string) {
const [file, root] = Git.splitPath(fileName, repoPath);
return git({ cwd: root }, 'checkout', sha, '--', file);
return git<string>({ cwd: root }, 'checkout', sha, '--', file);
}
static async config_get(key: string, repoPath?: string) {
const data = await git(
const data = await git<string>(
{ cwd: repoPath || '', exceptionHandler: ignoreExceptionsHandler },
'config',
'--get',
@ -406,7 +410,7 @@ export class Git {
}
static async config_getRegex(pattern: string, repoPath?: string) {
const data = await git(
const data = await git<string>(
{ cwd: repoPath || '', exceptionHandler: ignoreExceptionsHandler },
'config',
'--get-regex',
@ -425,7 +429,7 @@ export class Git {
}
const encoding: BufferEncoding = options.encoding === 'utf8' ? 'utf8' : 'binary';
return git({ cwd: repoPath, encoding: encoding }, ...params, '--', fileName);
return git<string>({ cwd: repoPath, encoding: encoding }, ...params, '--', fileName);
}
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string, options: { filter?: string } = {}) {
@ -440,7 +444,7 @@ export class Git {
params.push(sha2);
}
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static diff_shortstat(repoPath: string, sha?: string) {
@ -448,7 +452,7 @@ export class Git {
if (sha) {
params.push(sha);
}
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static difftool_dirDiff(repoPath: string, tool: string, ref1: string, ref2?: string) {
@ -457,7 +461,7 @@ export class Git {
params.push(ref2);
}
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static difftool_fileDiff(repoPath: string, fileName: string, tool: string, staged: boolean) {
@ -467,7 +471,7 @@ export class Git {
}
params.push('--', fileName);
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static log(repoPath: string, options: { author?: string; maxCount?: number; ref?: string; reverse?: boolean }) {
@ -486,7 +490,7 @@ export class Git {
params.push(options.ref);
}
}
return git({ cwd: repoPath }, ...params, '--');
return git<string>({ cwd: repoPath }, ...params, '--');
}
static log_file(
@ -525,11 +529,11 @@ export class Git {
params.push(`-L ${options.startLine},${options.endLine}:${file}`);
}
return git({ cwd: root }, ...params, '--', file);
return git<string>({ cwd: root }, ...params, '--', file);
}
static async log_recent(repoPath: string, fileName: string) {
const data = await git(
const data = await git<string>(
{ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler },
'log',
'-M',
@ -542,7 +546,7 @@ export class Git {
}
static async log_resolve(repoPath: string, fileName: string, ref: string) {
const data = await git(
const data = await git<string>(
{ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler },
'log',
'-M',
@ -561,7 +565,7 @@ export class Git {
params.push(`-n${options.maxCount}`);
}
return git({ cwd: repoPath }, ...params, ...search);
return git<string>({ cwd: repoPath }, ...params, ...search);
}
static log_shortstat(repoPath: string, options: { ref?: string }) {
@ -569,7 +573,7 @@ export class Git {
if (options.ref && !Git.isStagedUncommitted(options.ref)) {
params.push(options.ref);
}
return git({ cwd: repoPath }, ...params, '--');
return git<string>({ cwd: repoPath }, ...params, '--');
}
static async ls_files(
@ -582,7 +586,23 @@ export class Git {
params.push(`--with-tree=${options.ref}`);
}
const data = await git({ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler }, ...params, fileName);
const data = await git<string>(
{ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler },
...params,
fileName
);
return data === '' ? undefined : data.trim();
}
static async ls_tree(repoPath: string, ref: string, options: { fileName?: string } = {}) {
const params = ['ls-tree'];
if (options.fileName) {
params.push('-l', ref, '--', options.fileName);
}
else {
params.push('-lrt', ref, '--');
}
const data = await git<string>({ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler }, ...params);
return data === '' ? undefined : data.trim();
}
@ -592,19 +612,19 @@ export class Git {
params.push('--fork-point');
}
return git({ cwd: repoPath }, ...params, ref1, ref2);
return git<string>({ cwd: repoPath }, ...params, ref1, ref2);
}
static remote(repoPath: string): Promise<string> {
return git({ cwd: repoPath }, 'remote', '-v');
return git<string>({ cwd: repoPath }, 'remote', '-v');
}
static remote_url(repoPath: string, remote: string): Promise<string> {
return git({ cwd: repoPath }, 'remote', 'get-url', remote);
return git<string>({ cwd: repoPath }, 'remote', 'get-url', remote);
}
static async revparse(repoPath: string, ref: string): Promise<string | undefined> {
const data = await git({ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler }, 'rev-parse', ref);
const data = await git<string>({ cwd: repoPath, exceptionHandler: ignoreExceptionsHandler }, 'rev-parse', ref);
return data === '' ? undefined : data.trim();
}
@ -617,13 +637,13 @@ export class Git {
} as GitCommandOptions;
try {
const data = await git(opts, ...params);
const data = await git<string>(opts, ...params);
return [data, undefined];
}
catch (ex) {
const msg = ex && ex.toString();
if (GitWarnings.headNotABranch.test(msg)) {
const data = await git(
const data = await git<string>(
{ ...opts, exceptionHandler: ignoreExceptionsHandler },
'log',
'-n1',
@ -641,7 +661,7 @@ export class Git {
if (result !== null) return [result[1], undefined];
if (GitWarnings.unknownRevision.test(msg)) {
const data = await git(
const data = await git<string>(
{ ...opts, exceptionHandler: ignoreExceptionsHandler },
'symbolic-ref',
'-q',
@ -657,16 +677,20 @@ export class Git {
}
static async revparse_toplevel(cwd: string): Promise<string | undefined> {
const data = await git({ cwd: cwd, exceptionHandler: ignoreExceptionsHandler }, 'rev-parse', '--show-toplevel');
const data = await git<string>(
{ cwd: cwd, exceptionHandler: ignoreExceptionsHandler },
'rev-parse',
'--show-toplevel'
);
return data === '' ? undefined : data.trim();
}
static async show(
static async show<TOut extends string | Buffer>(
repoPath: string | undefined,
fileName: string,
ref: string,
options: { encoding?: string } = {}
): Promise<string | undefined> {
): Promise<TOut | undefined> {
const [file, root] = Git.splitPath(fileName, repoPath);
if (Git.isStagedUncommitted(ref)) {
@ -682,13 +706,13 @@ export class Git {
const args = ref.endsWith(':') ? `${ref}./${file}` : `${ref}:./${file}`;
try {
const data = await git(opts, 'show', args, '--');
const data = await git<TOut>(opts, 'show', args, '--'); // , '--binary', '--no-textconv'
return data;
}
catch (ex) {
const msg = ex && ex.toString();
if (ref === ':' && GitErrors.badRevision.test(msg)) {
return Git.show(repoPath, fileName, 'HEAD:', options);
return Git.show<TOut>(repoPath, fileName, 'HEAD:', options);
}
if (
@ -699,22 +723,22 @@ export class Git {
return undefined;
}
return defaultExceptionHandler(ex, opts, args);
return defaultExceptionHandler(ex, opts, args) as TOut;
}
}
static stash_apply(repoPath: string, stashName: string, deleteAfter: boolean) {
if (!stashName) return undefined;
return git({ cwd: repoPath }, 'stash', deleteAfter ? 'pop' : 'apply', stashName);
return git<string>({ cwd: repoPath }, 'stash', deleteAfter ? 'pop' : 'apply', stashName);
}
static stash_delete(repoPath: string, stashName: string) {
if (!stashName) return undefined;
return git({ cwd: repoPath }, 'stash', 'drop', stashName);
return git<string>({ cwd: repoPath }, 'stash', 'drop', stashName);
}
static stash_list(repoPath: string) {
return git({ cwd: repoPath }, ...defaultStashParams);
return git<string>({ cwd: repoPath }, ...defaultStashParams);
}
static stash_push(repoPath: string, pathspecs: string[], message?: string) {
@ -723,7 +747,7 @@ export class Git {
params.push('-m', message);
}
params.splice(params.length, 0, '--', ...pathspecs);
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static stash_save(repoPath: string, message?: string) {
@ -731,12 +755,12 @@ export class Git {
if (message) {
params.push(message);
}
return git({ cwd: repoPath }, ...params);
return git<string>({ cwd: repoPath }, ...params);
}
static status(repoPath: string, porcelainVersion: number = 1): Promise<string> {
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
return git(
return git<string>(
{ cwd: repoPath, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' } },
'-c',
'color.status=false',
@ -751,7 +775,7 @@ export class Git {
const [file, root] = Git.splitPath(fileName, repoPath);
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
return git(
return git<string>(
{ cwd: root, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' } },
'-c',
'color.status=false',
@ -763,6 +787,6 @@ export class Git {
}
static tag(repoPath: string) {
return git({ cwd: repoPath }, 'tag', '-l', '-n1');
return git<string>({ cwd: repoPath }, 'tag', '-l', '-n1');
}
}

+ 3
- 3
src/git/gitLocator.ts ファイルの表示

@ -13,7 +13,7 @@ function parseVersion(raw: string): string {
}
async function findSpecificGit(path: string): Promise<IGitInfo> {
const version = await run(path, ['--version'], 'utf8');
const version = await run<string>(path, ['--version'], 'utf8');
// If needed, let's update our path to avoid the search on every command
if (!path || path === 'git') {
path = findExecutable(path, ['--version']).cmd;
@ -27,7 +27,7 @@ async function findSpecificGit(path: string): Promise {
async function findGitDarwin(): Promise<IGitInfo> {
try {
let path = await run('which', ['git'], 'utf8');
let path = await run<string>('which', ['git'], 'utf8');
path = path.replace(/^\s+|\s+$/g, '');
if (path !== '/usr/bin/git') {
@ -35,7 +35,7 @@ async function findGitDarwin(): Promise {
}
try {
await run('xcode-select', ['-p'], 'utf8');
await run<string>('xcode-select', ['-p'], 'utf8');
return findSpecificGit(path);
}
catch (ex) {

+ 37
- 20
src/git/gitUri.ts ファイルの表示

@ -30,6 +30,8 @@ interface UriEx {
new (components: UriComponents): Uri;
}
const stripRepoRevisionFromPathRegex = /\/[^\/]+\/?(.*)/;
export class GitUri extends ((Uri as any) as UriEx) {
repoPath?: string;
sha?: string;
@ -45,18 +47,25 @@ export class GitUri extends ((Uri as any) as UriEx) {
return;
}
if (uri.scheme === DocumentSchemes.GitLensGit) {
const data: IUriRevisionData = JSON.parse(uri.query);
if (uri.scheme === DocumentSchemes.GitLens) {
const data = JSON.parse(uri.query) as IUriRevisionData;
const [authority, fsPath] = GitUri.ensureValidUNCPath(
uri.authority,
path.resolve(data.repoPath, data.fileName)
data.repoPath = Strings.normalizePath(data.repoPath);
data.path = Strings.normalizePath(
`/${data.repoPath}/${uri.path.replace(stripRepoRevisionFromPathRegex, '$1')}`
);
super({ scheme: uri.scheme, authority: authority, path: fsPath, query: uri.query, fragment: uri.fragment });
super({
scheme: uri.scheme,
authority: uri.authority,
path: data.path,
query: JSON.stringify(data),
fragment: uri.fragment
});
this.repoPath = data.repoPath;
if (GitService.isStagedUncommitted(data.sha) || !GitService.isUncommitted(data.sha)) {
this.sha = data.sha;
if (GitService.isStagedUncommitted(data.ref) || !GitService.isUncommitted(data.ref)) {
this.sha = data.ref;
}
return;
@ -131,7 +140,10 @@ export class GitUri extends ((Uri as any) as UriEx) {
private static ensureValidUNCPath(authority: string, fsPath: string): [string, string] {
// Taken from https://github.com/Microsoft/vscode/blob/master/src/vs/base/common/uri.ts#L239-L251
// check for authority as used in UNC shares or use the path as given
if (fsPath[0] === '\\' && fsPath[1] === '\\') {
if (
fsPath.charCodeAt(0) === Strings.CharCode.Backslash &&
fsPath.charCodeAt(1) === Strings.CharCode.Backslash
) {
const index = fsPath.indexOf('\\', 2);
if (index === -1) {
authority = fsPath.substring(2);
@ -175,7 +187,7 @@ export class GitUri extends ((Uri as any) as UriEx) {
if (!Container.git.isTrackable(uri)) return new GitUri(uri);
if (uri.scheme === DocumentSchemes.GitLensGit) return new GitUri(uri);
if (uri.scheme === DocumentSchemes.GitLens) return new GitUri(uri);
// If this is a git uri, find its repoPath
if (uri.scheme === DocumentSchemes.Git) {
@ -300,23 +312,28 @@ export class GitUri extends ((Uri as any) as UriEx) {
shortSha = uriOrSha.shortSha;
}
repoPath = Strings.normalizePath(repoPath!);
const repoName = path.basename(repoPath);
const data: IUriRevisionData = {
fileName: Strings.normalizePath(path.relative(repoPath!, fileName)),
repoPath: repoPath!,
sha: sha
path: Strings.normalizePath(fileName, { addLeadingSlash: true }),
ref: sha,
repoPath: repoPath
};
const parsed = path.parse(fileName);
return Uri.parse(
`${DocumentSchemes.GitLensGit}:${path.join(parsed.dir, parsed.name)} (${shortSha})${
parsed.ext
}?${JSON.stringify(data)}`
let filePath = Strings.normalizePath(path.relative(repoPath, fileName), { addLeadingSlash: true });
if (filePath === '/') {
filePath = '';
}
const uri = Uri.parse(
`${DocumentSchemes.GitLens}://git/${repoName}@${shortSha}${filePath}?${JSON.stringify(data)}`
);
return uri;
}
}
interface IUriRevisionData {
sha?: string;
fileName: string;
path: string;
ref?: string;
repoPath: string;
}

+ 1
- 0
src/git/models/models.ts ファイルの表示

@ -13,3 +13,4 @@ export * from './stash';
export * from './stashCommit';
export * from './status';
export * from './tag';
export * from './tree';

+ 1
- 1
src/git/models/repository.ts ファイルの表示

@ -12,9 +12,9 @@ import {
} from 'vscode';
import { configuration, IRemotesConfig } from '../../configuration';
import { Container } from '../../container';
import { GitUri } from '../../gitService';
import { Functions } from '../../system';
import { GitBranch, GitDiffShortStat, GitRemote, GitStash, GitStatus, GitTag } from '../git';
import { GitUri } from '../gitUri';
import { RemoteProviderFactory, RemoteProviderMap } from '../remotes/factory';
export enum RepositoryChange {

+ 8
- 0
src/git/models/tree.ts ファイルの表示

@ -0,0 +1,8 @@
'use strict';
export interface GitTree {
commitSha: string;
path: string;
size: number;
type: 'blob' | 'tree';
}

+ 1
- 0
src/git/parsers/parsers.ts ファイルの表示

@ -8,3 +8,4 @@ export * from './remoteParser';
export * from './stashParser';
export * from './statusParser';
export * from './tagParser';
export * from './treeParser';

+ 32
- 0
src/git/parsers/treeParser.ts ファイルの表示

@ -0,0 +1,32 @@
'use strict';
import { GitTree } from './../git';
const treeRegex = /(?:.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+)/gm;
export class GitTreeParser {
static parse(data: string | undefined): GitTree[] | undefined {
if (!data) return undefined;
const trees: GitTree[] = [];
let match: RegExpExecArray | null = null;
do {
match = treeRegex.exec(data);
if (match == null) break;
const [, type, commitSha, size, filePath] = match;
trees.push({
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
commitSha: commitSha === undefined ? '' : (' ' + commitSha).substr(1),
path: filePath === undefined ? '' : filePath,
size: size === '-' ? 0 : Number(size || 0),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
type: (type === undefined ? '' : (' ' + type).substr(1)) as 'blob' | 'tree'
});
} while (match != null);
if (!trees.length) return undefined;
return trees;
}
}

+ 1
- 1
src/git/remotes/provider.ts ファイルの表示

@ -1,8 +1,8 @@
'use strict';
import { commands, Range, Uri, window } from 'vscode';
import { BuiltInCommands } from '../../constants';
import { GitLogCommit } from '../../gitService';
import { Logger } from '../../logger';
import { GitLogCommit } from '../models/logCommit';
export enum RemoteResourceType {
Branch = 'branch',

+ 11
- 6
src/git/shell.ts ファイルの表示

@ -104,7 +104,7 @@ export class RunError extends Error {
export interface RunOptions {
readonly cwd?: string;
readonly env?: Object;
readonly encoding?: BufferEncoding;
readonly encoding?: BufferEncoding | 'buffer';
/**
* The size the output buffer to allocate to the spawned process. Set this
* if you are anticipating a large amount of output.
@ -126,10 +126,15 @@ export interface RunOptions {
readonly stdinEncoding?: string;
}
export function run(command: string, args: any[], encoding: BufferEncoding, options: RunOptions = {}): Promise<string> {
export function run<TOut extends string | Buffer>(
command: string,
args: any[],
encoding: BufferEncoding | 'buffer',
options: RunOptions = {}
): Promise<TOut> {
const { stdin, stdinEncoding, ...opts } = { maxBuffer: 100 * 1024 * 1024, ...options } as RunOptions;
return new Promise<string>((resolve, reject) => {
return new Promise<TOut>((resolve, reject) => {
const proc = execFile(
command,
args,
@ -155,9 +160,9 @@ export function run(command: string, args: any[], encoding: BufferEncoding, opti
}
resolve(
encoding === 'utf8' || encoding === 'binary'
? stdout
: iconv.decode(Buffer.from(stdout, 'binary'), encoding)
encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer'
? (stdout as TOut)
: (iconv.decode(Buffer.from(stdout, 'binary'), encoding) as TOut)
);
}
);

+ 0
- 32
src/gitContentProvider.ts ファイルの表示

@ -1,32 +0,0 @@
'use strict';
import * as path from 'path';
import { CancellationToken, TextDocumentContentProvider, Uri, window, workspace } from 'vscode';
import { DocumentSchemes } from './constants';
import { GitService, GitUri } from './gitService';
import { Logger } from './logger';
export class GitContentProvider implements TextDocumentContentProvider {
static scheme = DocumentSchemes.GitLensGit;
async provideTextDocumentContent(uri: Uri, token: CancellationToken): Promise<string | undefined> {
const gitUri = GitUri.fromRevisionUri(uri);
if (!gitUri.repoPath || gitUri.sha === GitService.deletedSha) return '';
try {
const document = await workspace.openTextDocument(
Uri.parse(`git:/${gitUri.fsPath}?${JSON.stringify({ path: gitUri.fsPath, ref: gitUri.sha || 'HEAD' })}`)
);
return document.getText();
}
catch (ex) {
Logger.error(ex, 'GitContentProvider', 'getVersionedFileText');
window.showErrorMessage(
`Unable to show Git revision ${GitService.shortenSha(gitUri.sha)} of '${path.relative(
gitUri.repoPath,
gitUri.fsPath
)}'`
);
return undefined;
}
}
}

+ 47
- 27
src/gitService.ts ファイルの表示

@ -18,7 +18,7 @@ import {
} from 'vscode';
import { GitExtension } from './@types/git';
import { configuration, IRemotesConfig } from './configuration';
import { CommandContext, DocumentSchemes, GlyphChars, ImageMimetypes, setCommandContext } from './constants';
import { CommandContext, DocumentSchemes, GlyphChars, setCommandContext } from './constants';
import { Container } from './container';
import {
CommitFormatting,
@ -49,6 +49,8 @@ import {
GitStatusParser,
GitTag,
GitTagParser,
GitTree,
GitTreeParser,
Repository,
RepositoryChange
} from './git/git';
@ -191,18 +193,25 @@ export class GitService implements Disposable {
if (f.uri.scheme !== DocumentSchemes.File) continue;
const fsPath = f.uri.fsPath;
const filteredTree = this._repositoryTree.findSuperstr(fsPath);
const repos = this._repositoryTree.findSuperstr(fsPath);
const reposToDelete =
filteredTree !== undefined
repos !== undefined
? // Since the filtered tree will have keys that are relative to the fsPath, normalize to the full path
[
...Iterables.map<[Repository, string], [Repository, string]>(
filteredTree.entries(),
([r, k]) => [r, path.join(fsPath, k)]
)
]
[...Iterables.map<Repository, [Repository, string]>(repos, r => [r, r.path])]
: [];
// const filteredTree = this._repositoryTree.findSuperstr(fsPath);
// const reposToDelete =
// filteredTree !== undefined
// ? // Since the filtered tree will have keys that are relative to the fsPath, normalize to the full path
// [
// ...Iterables.map<[Repository, string], [Repository, string]>(
// filteredTree.entries(),
// ([r, k]) => [r, path.join(fsPath, k)]
// )
// ]
// : [];
const repo = this._repositoryTree.get(fsPath);
if (repo !== undefined) {
reposToDelete.push([repo, fsPath]);
@ -1648,6 +1657,25 @@ export class GitService implements Disposable {
return GitTagParser.parse(data, repoPath) || [];
}
async getTreeFileForRevision(repoPath: string, fileName: string, ref: string): Promise<GitTree | undefined> {
if (repoPath === undefined) return undefined;
Logger.log(`getTreeFileForRevision('${repoPath}', '${fileName}', '${ref}')`);
const data = await Git.ls_tree(repoPath, ref, { fileName: fileName });
const trees = GitTreeParser.parse(data);
return trees === undefined || trees.length === 0 ? undefined : trees[0];
}
async getTreeForRevision(repoPath: string, ref: string): Promise<GitTree[]> {
if (repoPath === undefined) return [];
Logger.log(`getTreeForRevision('${repoPath}', '${ref}')`);
const data = await Git.ls_tree(repoPath, ref);
return GitTreeParser.parse(data) || [];
}
async getVersionedFile(
repoPath: string | undefined,
fileName: string,
@ -1663,27 +1691,21 @@ export class GitService implements Disposable {
return undefined;
}
if (ImageMimetypes[path.extname(fileName)]) {
const file = await Git.getVersionedFile(repoPath, fileName, sha);
if (file === undefined) return undefined;
this._versionedUriCache.set(
GitUri.toKey(file),
new GitUri(Uri.file(fileName), { sha: sha, repoPath: repoPath!, versionedPath: file })
);
return Uri.file(file);
}
return GitUri.toRevisionUri(sha, fileName, repoPath!);
}
getVersionedFileText(repoPath: string, fileName: string, sha: string) {
Logger.log(`getVersionedFileText('${repoPath}', '${fileName}', ${sha})`);
getVersionedFileBuffer(repoPath: string, fileName: string, sha: string) {
Logger.log(`getVersionedFileBuffer('${repoPath}', '${fileName}', ${sha})`);
return Git.show(repoPath, fileName, sha, { encoding: GitService.getEncoding(repoPath, fileName) });
return Git.show<Buffer>(repoPath, fileName, sha, { encoding: 'buffer' });
}
// getVersionedFileText(repoPath: string, fileName: string, sha: string) {
// Logger.log(`getVersionedFileText('${repoPath}', '${fileName}', ${sha})`);
// return Git.show<string>(repoPath, fileName, sha, { encoding: GitService.getEncoding(repoPath, fileName) });
// }
getVersionedUri(uri: Uri) {
return this._versionedUriCache.get(GitUri.toKey(uri));
}
@ -1699,9 +1721,7 @@ export class GitService implements Disposable {
scheme = schemeOruri.scheme;
}
return (
scheme === DocumentSchemes.File || scheme === DocumentSchemes.Git || scheme === DocumentSchemes.GitLensGit
);
return scheme === DocumentSchemes.File || scheme === DocumentSchemes.Git || scheme === DocumentSchemes.GitLens;
}
async isTracked(

+ 48
- 22
src/system/searchTree.ts ファイルの表示

@ -1,5 +1,6 @@
'use strict';
import { Iterables } from '../system/iterable';
import { Iterables } from './iterable';
import { Strings } from './string';
// Code stolen from https://github.com/Microsoft/vscode/blob/b3e6d5bb039a4a9362b52a2c8726267ca68cf64e/src/vs/base/common/map.ts#L352
@ -42,17 +43,6 @@ export class StringIterator implements IKeyIterator {
}
}
const enum CharCode {
/**
* The `/` character.
*/
Slash = 47,
/**
* The `\` character.
*/
Backslash = 92
}
export class PathIterator implements IKeyIterator {
private _value!: string;
private _from!: number;
@ -75,7 +65,7 @@ export class PathIterator implements IKeyIterator {
let justSeps = true;
for (; this._to < this._value.length; this._to++) {
const ch = this._value.charCodeAt(this._to);
if (ch === CharCode.Slash || ch === CharCode.Backslash) {
if (ch === Strings.CharCode.Slash || ch === Strings.CharCode.Backslash) {
if (justSeps) {
this._from++;
}
@ -301,7 +291,7 @@ export class TernarySearchTree {
return (node && node.value) || candidate;
}
findSuperstr(key: string): TernarySearchTree<E> | undefined {
findSuperstr(key: string, limit: boolean = false): Iterable<E> | undefined {
const iter = this._iter.reset(key);
let node = this._root;
while (node) {
@ -324,34 +314,70 @@ export class TernarySearchTree {
if (!node.mid) {
return undefined;
}
const ret = new TernarySearchTree<E>(this._iter);
ret._root = node.mid;
return ret;
else {
node = node.mid;
return {
[Symbol.iterator]: () => this._nodeIterator(node!, limit)
};
}
}
}
return undefined;
}
private _nodeIterator(node: TernarySearchTreeNode<E>, limit: boolean = false): Iterator<E> {
const res = {
done: false,
value: undefined! as E
};
let idx: number;
let data: E[];
const next = () => {
if (!data) {
// lazy till first invocation
data = [];
idx = 0;
this._forEach(node, value => data.push(value), limit);
}
if (idx >= data.length) {
res.done = true;
res.value = undefined!;
}
else {
res.done = false;
res.value = data[idx++];
}
return res;
};
return { next };
}
forEach(callback: (value: E, index: string) => any) {
this._forEach(this._root!, callback);
}
private _forEach(node: TernarySearchTreeNode<E>, callback: (value: E, index: string) => any) {
private _forEach(
node: TernarySearchTreeNode<E>,
callback: (value: E, index: string) => any,
limit: boolean = false
) {
if (node === undefined) return;
// left
this._forEach(node.left!, callback);
this._forEach(node.left!, callback, limit);
// node
if (node.value) {
callback(node.value, node.key);
}
// mid
this._forEach(node.mid!, callback);
if (!limit) {
// mid
this._forEach(node.mid!, callback, limit);
}
// right
this._forEach(node.right!, callback);
this._forEach(node.right!, callback, limit);
}
any(): boolean {

+ 37
- 12
src/system/string.ts ファイルの表示

@ -2,14 +2,26 @@
import { createHash, HexBase64Latin1Encoding } from 'crypto';
export namespace Strings {
export const enum CharCode {
/**
* The `/` character.
*/
Slash = 47,
/**
* The `\` character.
*/
Backslash = 92
}
export function getDurationMilliseconds(start: [number, number]) {
const [secs, nanosecs] = process.hrtime(start);
return secs * 1000 + Math.floor(nanosecs / 1000000);
}
const pathNormalizer = /\\/g;
const TokenRegex = /\$\{(\W*)?([^|]*?)(?:\|(\d+)(\-|\?)?)?(\W*)?\}/g;
const TokenSanitizeRegex = /\$\{(?:\W*)?(\w*?)(?:[\W\d]*)\}/g;
const pathNormalizeRegex = /\\/g;
const pathStripTrailingSlashRegex = /\/$/g;
const tokenRegex = /\$\{(\W*)?([^|]*?)(?:\|(\d+)(\-|\?)?)?(\W*)?\}/g;
const tokenSanitizeRegex = /\$\{(?:\W*)?(\w*?)(?:[\W\d]*)\}/g;
export interface ITokenOptions {
collapseWhitespace: boolean;
@ -22,7 +34,7 @@ export namespace Strings {
export function getTokensFromTemplate(template: string) {
const tokens: { key: string; options: ITokenOptions }[] = [];
let match = TokenRegex.exec(template);
let match = tokenRegex.exec(template);
while (match != null) {
const [, prefix, key, truncateTo, option, suffix] = match;
tokens.push({
@ -35,7 +47,7 @@ export namespace Strings {
truncateTo: truncateTo == null ? undefined : parseInt(truncateTo, 10)
}
});
match = TokenRegex.exec(template);
match = tokenRegex.exec(template);
}
return tokens;
@ -43,9 +55,9 @@ export namespace Strings {
export function interpolate(template: string, context: object | undefined): string {
if (!template) return template;
if (context === undefined) return template.replace(TokenSanitizeRegex, '');
if (context === undefined) return template.replace(tokenSanitizeRegex, '');
template = template.replace(TokenSanitizeRegex, '$${this.$1}');
template = template.replace(tokenSanitizeRegex, '$${this.$1}');
return new Function(`return \`${template}\`;`).call(context);
}
@ -68,11 +80,24 @@ export namespace Strings {
.digest(encoding);
}
export function normalizePath(fileName: string) {
const normalized = fileName && fileName.replace(pathNormalizer, '/');
// if (normalized && normalized.includes('..')) {
// debugger;
// }
export function normalizePath(
fileName: string,
options: { addLeadingSlash?: boolean; stripTrailingSlash?: boolean } = { stripTrailingSlash: true }
) {
if (fileName == null || fileName === '') return fileName;
let normalized = fileName.replace(pathNormalizeRegex, '/');
const { addLeadingSlash, stripTrailingSlash } = { stripTrailingSlash: true, ...options };
if (stripTrailingSlash) {
normalized = normalized.replace(pathStripTrailingSlashRegex, '');
}
if (addLeadingSlash && normalized.charCodeAt(0) !== CharCode.Slash) {
normalized = `/${normalized}`;
}
return normalized;
}

+ 15
- 1
src/views/explorerCommands.ts ファイルの表示

@ -1,4 +1,5 @@
'use strict';
import * as path from 'path';
import { commands, Disposable, InputBoxOptions, Terminal, TextDocumentShowOptions, Uri, window } from 'vscode';
import {
Commands,
@ -8,10 +9,12 @@ import {
DiffWithWorkingCommandArgs,
openEditor,
OpenFileInRemoteCommandArgs,
OpenFileRevisionCommandArgs
OpenFileRevisionCommandArgs,
openWorkspace
} from '../commands';
import { CommandContext, extensionTerminalName, setCommandContext } from '../constants';
import { Container } from '../container';
import { toGitLensFSUri } from '../git/fsProvider';
import { GitService, GitUri } from '../gitService';
import { Arrays } from '../system';
import {
@ -47,6 +50,8 @@ export class ExplorerCommands implements Disposable {
private _terminalCwd: string | undefined;
constructor() {
commands.registerCommand('gitlens.explorers.exploreRepoRevision', this.exploreRepoRevision, this);
commands.registerCommand('gitlens.explorers.openChanges', this.openChanges, this);
commands.registerCommand('gitlens.explorers.openChangesWithWorking', this.openChangesWithWorking, this);
commands.registerCommand('gitlens.explorers.openFile', this.openFile, this);
@ -184,6 +189,15 @@ export class ExplorerCommands implements Disposable {
setCommandContext(CommandContext.ExplorersCanCompare, true);
}
private exploreRepoRevision(node: ExplorerRefNode, options: { openInNewWindow?: boolean } = {}) {
if (!(node instanceof ExplorerRefNode)) return;
const uri = toGitLensFSUri(node.ref, node.repoPath);
const gitUri = GitUri.fromRevisionUri(uri);
openWorkspace(uri, `${path.basename(gitUri.repoPath!)} @ ${gitUri.shortSha}`, options);
}
private openChanges(node: CommitNode | StashNode) {
const command = node.getCommand();
if (command === undefined || command.arguments === undefined) return;

読み込み中…
キャンセル
保存