Quellcode durchsuchen

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 vor 6 Jahren
Ursprung
Commit
4320f5342c
22 geänderte Dateien mit 735 neuen und 361 gelöschten Zeilen
  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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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 Datei anzeigen

@ -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;

Laden…
Abbrechen
Speichern