Merge branch 'ads-master-vscode-2020-05-06T02-35-47'

This commit is contained in:
Anthony Dresser
2020-05-05 23:21:01 -07:00
243 changed files with 4237 additions and 2479 deletions
-6
View File
@@ -1,6 +0,0 @@
{
"useTabs": true,
"printWidth": 120,
"semi": true,
"singleQuote": true
}
+1 -1
View File
@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron" disturl "https://atom.io/download/electron"
target "7.2.2" target "7.2.4"
runtime "electron" runtime "electron"
+1 -1
View File
@@ -44,7 +44,7 @@ function prepareDebPackage(arch) {
.pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME_SHORT@@', product.nameShort))
.pipe(replace('@@NAME@@', product.applicationName)) .pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`)) .pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`))
.pipe(replace('@@ICON@@', `/usr/share/pixmaps/${product.linuxIconName}.png`)) .pipe(replace('@@ICON@@', product.linuxIconName))
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' }) const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' })
+1 -1
View File
@@ -48,7 +48,7 @@
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",
"terser": "4.3.8", "terser": "4.3.8",
"typescript": "^3.9.0-dev.20200427", "typescript": "^3.9.1-rc",
"vsce": "1.48.0", "vsce": "1.48.0",
"vscode-telemetry-extractor": "^1.5.4", "vscode-telemetry-extractor": "^1.5.4",
"xml2js": "^0.4.17" "xml2js": "^0.4.17"
+4 -4
View File
@@ -3462,10 +3462,10 @@ typescript@^3.0.1:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^3.9.0-dev.20200427: typescript@^3.9.1-rc:
version "3.9.0-dev.20200427" version "3.9.1-rc"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200427.tgz#e42d606d938575dfb7b0b66f04a31b5f0eb0be57" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.1-rc.tgz#81d5a5a0a597e224b6e2af8dffb46524b2eaf5f3"
integrity sha512-ja/GhL7BHT+VQZiLoYMGJt2CP1Pdr0EhYefv4LLw4tVooSuCDB8SDKT/i/HwsoPgQ4ZaYfg1vPl+1RhiO3bwJg== integrity sha512-+cPv8L2Vd4KidCotqi2wjegBZ5n47CDRUu/QiLVu2YbeXAz78hIfcai9ziBiNI6JTGTVwUqXRug2UZxDcxhvFw==
typical@^4.0.0: typical@^4.0.0:
version "4.0.0" version "4.0.0"
+2 -2
View File
@@ -60,12 +60,12 @@
"git": { "git": {
"name": "electron", "name": "electron",
"repositoryUrl": "https://github.com/electron/electron", "repositoryUrl": "https://github.com/electron/electron",
"commitHash": "959e80cc53cbebf8eb1d62eb2d14fa8fd86b0394" "commitHash": "0552e0d5de46ffa3b481d741f1db5c779e201565"
} }
}, },
"isOnlyProductionDependency": true, "isOnlyProductionDependency": true,
"license": "MIT", "license": "MIT",
"version": "7.2.2" "version": "7.2.4"
}, },
{ {
"component": { "component": {
@@ -282,6 +282,8 @@
] ]
} }
}, },
"oneOf": [
{
"allOf": [ "allOf": [
{ {
"oneOf": [ "oneOf": [
@@ -311,4 +313,11 @@
"$ref": "#/definitions/devContainerCommon" "$ref": "#/definitions/devContainerCommon"
} }
] ]
},
{
"type": "object",
"$ref": "#/definitions/devContainerCommon",
"additionalProperties": false
}
]
} }
@@ -133,7 +133,6 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
webview: vscode.WebviewPanel, webview: vscode.WebviewPanel,
state: any state: any
): Promise<void> { ): Promise<void> {
console.log(state);
const resource = vscode.Uri.parse(state.resource); const resource = vscode.Uri.parse(state.resource);
const locked = state.locked; const locked = state.locked;
const line = state.line; const line = state.line;
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "0.0.1", "version": "0.0.1",
"description": "Dependencies shared by all extensions", "description": "Dependencies shared by all extensions",
"dependencies": { "dependencies": {
"typescript": "3.8.3" "typescript": "3.9.1-rc"
}, },
"scripts": { "scripts": {
"postinstall": "node ./postinstall" "postinstall": "node ./postinstall"
+4 -4
View File
@@ -2,7 +2,7 @@
# yarn lockfile v1 # yarn lockfile v1
typescript@3.8.3: typescript@3.9.1-rc:
version "3.8.3" version "3.9.1-rc"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.1-rc.tgz#81d5a5a0a597e224b6e2af8dffb46524b2eaf5f3"
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== integrity sha512-+cPv8L2Vd4KidCotqi2wjegBZ5n47CDRUu/QiLVu2YbeXAz78hIfcai9ziBiNI6JTGTVwUqXRug2UZxDcxhvFw==
+7 -7
View File
@@ -81,11 +81,11 @@
"vscode-ripgrep": "^1.5.8", "vscode-ripgrep": "^1.5.8",
"vscode-sqlite3": "4.0.10", "vscode-sqlite3": "4.0.10",
"vscode-textmate": "5.1.1", "vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.25", "xterm": "4.6.0-beta.38",
"xterm-addon-search": "0.6.0", "xterm-addon-search": "0.7.0-beta.2",
"xterm-addon-unicode11": "0.2.0-beta.2", "xterm-addon-unicode11": "0.2.0-beta.5",
"xterm-addon-web-links": "0.3.0", "xterm-addon-web-links": "0.4.0-beta.5",
"xterm-addon-webgl": "0.7.0-beta.8", "xterm-addon-webgl": "0.7.0-beta.10",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
"yazl": "^2.4.3", "yazl": "^2.4.3",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
@@ -126,7 +126,7 @@
"css-loader": "^3.2.0", "css-loader": "^3.2.0",
"debounce": "^1.0.0", "debounce": "^1.0.0",
"deemon": "^1.4.0", "deemon": "^1.4.0",
"electron": "7.2.2", "electron": "7.2.4",
"eslint": "6.8.0", "eslint": "6.8.0",
"eslint-plugin-jsdoc": "^19.1.0", "eslint-plugin-jsdoc": "^19.1.0",
"event-stream": "3.3.4", "event-stream": "3.3.4",
@@ -183,7 +183,7 @@
"temp-write": "^3.4.0", "temp-write": "^3.4.0",
"ts-loader": "^4.4.2", "ts-loader": "^4.4.2",
"typemoq": "^0.3.2", "typemoq": "^0.3.2",
"typescript": "^3.9.0-dev.20200427", "typescript": "^3.9.1-rc",
"typescript-formatter": "7.1.0", "typescript-formatter": "7.1.0",
"underscore": "^1.8.2", "underscore": "^1.8.2",
"vinyl": "^2.0.0", "vinyl": "^2.0.0",
+5 -5
View File
@@ -38,11 +38,11 @@
"vscode-proxy-agent": "^0.5.2", "vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8", "vscode-ripgrep": "^1.5.8",
"vscode-textmate": "5.1.1", "vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.25", "xterm": "4.6.0-beta.38",
"xterm-addon-search": "0.6.0", "xterm-addon-search": "0.7.0-beta.2",
"xterm-addon-unicode11": "0.2.0-beta.2", "xterm-addon-unicode11": "0.2.0-beta.5",
"xterm-addon-web-links": "0.3.0", "xterm-addon-web-links": "0.4.0-beta.5",
"xterm-addon-webgl": "0.7.0-beta.8", "xterm-addon-webgl": "0.7.0-beta.10",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
"yazl": "^2.4.3", "yazl": "^2.4.3",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
+5 -5
View File
@@ -23,11 +23,11 @@
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33", "slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"vscode-oniguruma": "1.3.0", "vscode-oniguruma": "1.3.0",
"vscode-textmate": "5.1.1", "vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.25", "xterm": "4.6.0-beta.38",
"xterm-addon-search": "0.6.0", "xterm-addon-search": "0.7.0-beta.2",
"xterm-addon-unicode11": "0.2.0-beta.2", "xterm-addon-unicode11": "0.2.0-beta.5",
"xterm-addon-web-links": "0.3.0", "xterm-addon-web-links": "0.4.0-beta.5",
"xterm-addon-webgl": "0.7.0-beta.8", "xterm-addon-webgl": "0.7.0-beta.10",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
} }
} }
+20 -20
View File
@@ -353,30 +353,30 @@ xtend@^4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xterm-addon-search@0.6.0: xterm-addon-search@0.7.0-beta.2:
version "0.6.0" version "0.7.0-beta.2"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.6.0.tgz#542cc2c35e83e7332ce1982b65ad218ee769836c" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.7.0-beta.2.tgz#384bda136c707f97a77eefc76cc7d9e572ce0719"
integrity sha512-k3EsZzUptCXygHFP5rQuCBdWWkI/ZNuX3pDSOVdxPV9jB7U5Aha9guTIZoMP7FIjL8jce+ClQs6q7VINcRV1+w== integrity sha512-A9fyiBBvG6ZNIwSJ03+sRCv9y20/uzd1wjCoaYUqp9fu3YGiHaGwyo9rAfm2M/fQM5vBmyJk4Qw/lwVq7TtlAw==
xterm-addon-unicode11@0.2.0-beta.2: xterm-addon-unicode11@0.2.0-beta.5:
version "0.2.0-beta.2" version "0.2.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.2.tgz#2a13ba5b08fdb1005be241816c4e3302674db4af" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.5.tgz#5961850162df20b5e966166423cd6957ac2db298"
integrity sha512-Y047mnIWrAj65TpStdyPYoPeDTX4en+XX4Y90KuQB3cW2xIyZj25NSVV9BZdqzSb7gk9M6KBvIcm8chj7S2N8Q== integrity sha512-IjnbBcyfS5JgJDXPO0W2nk/VBtGwx6GWE2snMC676z4DmAABUqPXfTzJKfUoWqoT6UcbxB0oIjDzykCfoRJp6Q==
xterm-addon-web-links@0.3.0: xterm-addon-web-links@0.4.0-beta.5:
version "0.3.0" version "0.4.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0-beta.5.tgz#523fd0a1c5668370d73e05019ed16eaf596894c8"
integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A== integrity sha512-Qe0idPpSokCNvGrthSBjdrOZrsgXwnLYbzuv0JoEec/A9HVcxKmZ+ktw7fOA2gT/zbcwtrA5FWrir3GlRHglCQ==
xterm-addon-webgl@0.7.0-beta.8: xterm-addon-webgl@0.7.0-beta.10:
version "0.7.0-beta.8" version "0.7.0-beta.10"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.8.tgz#546651958d740bf05d6a05555fbcacd2759b2ee7" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.10.tgz#39fdb96351e97a1bf15f4c4c8944ba3d05cacee4"
integrity sha512-2jxMtRR5zgAar1gPqt0iD/+GOlZ3cHyzzbIbC77EBIdZZFuhEDhJkucVPPS2KPcyqw3VROL1FgX7BSEV2rvdeA== integrity sha512-nQl/ASk+ck11aSrBZXb2a0tu+SNDnm89owBk/sAZeZzi5MHNo6bB8y2VTKNNC6D3i3aFouTz4VorYB25LUgNFg==
xterm@4.6.0-beta.25: xterm@4.6.0-beta.38:
version "4.6.0-beta.25" version "4.6.0-beta.38"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.25.tgz#2faea6cf8c677ed545792562165604ce7f314026" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.38.tgz#8472b168941500c3071aba482c2b5c6040951ec7"
integrity sha512-63FLAUdJ8Bw9SMgLU3/r353P1WAtLxupbfvfddi4nMcz1WEGRq07O1CbmJn/bKHHkJw7gQQw0n1I8xnjFlLlTA== integrity sha512-Q+nOalMD1MDGOqXdtkGZmOQqbSBU+71vhlX2RBwQoSpJa1QBrKDAhSlN/J+/XvouvVEtCiEFDeacF4EufMEIMg==
zone.js@^0.8.4: zone.js@^0.8.4:
version "0.8.29" version "0.8.29"
+20 -20
View File
@@ -740,30 +740,30 @@ xtend@^4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xterm-addon-search@0.6.0: xterm-addon-search@0.7.0-beta.2:
version "0.6.0" version "0.7.0-beta.2"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.6.0.tgz#542cc2c35e83e7332ce1982b65ad218ee769836c" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.7.0-beta.2.tgz#384bda136c707f97a77eefc76cc7d9e572ce0719"
integrity sha512-k3EsZzUptCXygHFP5rQuCBdWWkI/ZNuX3pDSOVdxPV9jB7U5Aha9guTIZoMP7FIjL8jce+ClQs6q7VINcRV1+w== integrity sha512-A9fyiBBvG6ZNIwSJ03+sRCv9y20/uzd1wjCoaYUqp9fu3YGiHaGwyo9rAfm2M/fQM5vBmyJk4Qw/lwVq7TtlAw==
xterm-addon-unicode11@0.2.0-beta.2: xterm-addon-unicode11@0.2.0-beta.5:
version "0.2.0-beta.2" version "0.2.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.2.tgz#2a13ba5b08fdb1005be241816c4e3302674db4af" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.5.tgz#5961850162df20b5e966166423cd6957ac2db298"
integrity sha512-Y047mnIWrAj65TpStdyPYoPeDTX4en+XX4Y90KuQB3cW2xIyZj25NSVV9BZdqzSb7gk9M6KBvIcm8chj7S2N8Q== integrity sha512-IjnbBcyfS5JgJDXPO0W2nk/VBtGwx6GWE2snMC676z4DmAABUqPXfTzJKfUoWqoT6UcbxB0oIjDzykCfoRJp6Q==
xterm-addon-web-links@0.3.0: xterm-addon-web-links@0.4.0-beta.5:
version "0.3.0" version "0.4.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0-beta.5.tgz#523fd0a1c5668370d73e05019ed16eaf596894c8"
integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A== integrity sha512-Qe0idPpSokCNvGrthSBjdrOZrsgXwnLYbzuv0JoEec/A9HVcxKmZ+ktw7fOA2gT/zbcwtrA5FWrir3GlRHglCQ==
xterm-addon-webgl@0.7.0-beta.8: xterm-addon-webgl@0.7.0-beta.10:
version "0.7.0-beta.8" version "0.7.0-beta.10"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.8.tgz#546651958d740bf05d6a05555fbcacd2759b2ee7" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.10.tgz#39fdb96351e97a1bf15f4c4c8944ba3d05cacee4"
integrity sha512-2jxMtRR5zgAar1gPqt0iD/+GOlZ3cHyzzbIbC77EBIdZZFuhEDhJkucVPPS2KPcyqw3VROL1FgX7BSEV2rvdeA== integrity sha512-nQl/ASk+ck11aSrBZXb2a0tu+SNDnm89owBk/sAZeZzi5MHNo6bB8y2VTKNNC6D3i3aFouTz4VorYB25LUgNFg==
xterm@4.6.0-beta.25: xterm@4.6.0-beta.38:
version "4.6.0-beta.25" version "4.6.0-beta.38"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.25.tgz#2faea6cf8c677ed545792562165604ce7f314026" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.38.tgz#8472b168941500c3071aba482c2b5c6040951ec7"
integrity sha512-63FLAUdJ8Bw9SMgLU3/r353P1WAtLxupbfvfddi4nMcz1WEGRq07O1CbmJn/bKHHkJw7gQQw0n1I8xnjFlLlTA== integrity sha512-Q+nOalMD1MDGOqXdtkGZmOQqbSBU+71vhlX2RBwQoSpJa1QBrKDAhSlN/J+/XvouvVEtCiEFDeacF4EufMEIMg==
yauzl@^2.9.2: yauzl@^2.9.2:
version "2.10.0" version "2.10.0"
Regular → Executable
View File
+1 -1
View File
@@ -55,7 +55,7 @@ function code() {
function code-wsl() function code-wsl()
{ {
HOST_IP=$(powershell.exe -Command "& {(Get-NetIPAddress | Where-Object {\$_.InterfaceAlias -like '*WSL*' -and \$_.AddressFamily -eq 'IPv4'}).IPAddress | Write-Host -NoNewline}") HOST_IP=$(powershell.exe noprofile -Command "& {(Get-NetIPAddress | Where-Object {\$_.InterfaceAlias -like '*WSL*' -and \$_.AddressFamily -eq 'IPv4'}).IPAddress | Write-Host -NoNewline}")
export DISPLAY="$HOST_IP:0" export DISPLAY="$HOST_IP:0"
# in a wsl shell # in a wsl shell
@@ -165,7 +165,7 @@ export class ExtHostTreeView<T> extends vsTreeExt.ExtHostTreeView<T> {
}); });
} }
protected createTreeNode(element: T, extensionTreeItem: azdata.TreeComponentItem, parent?: vsTreeExt.TreeNode): vsTreeExt.TreeNode { protected createTreeNode(element: T, extensionTreeItem: azdata.TreeComponentItem, parent?: vsTreeExt.TreeNode | vsTreeExt.Root): vsTreeExt.TreeNode {
let node = super.createTreeNode(element, extensionTreeItem, parent); let node = super.createTreeNode(element, extensionTreeItem, parent);
if (node.item) { if (node.item) {
node.item = assign(node.item, { checked: extensionTreeItem.checked, enabled: extensionTreeItem.enabled }); node.item = assign(node.item, { checked: extensionTreeItem.checked, enabled: extensionTreeItem.enabled });
@@ -5,9 +5,8 @@
import 'vs/css!./media/dataExplorer.contribution'; import 'vs/css!./media/dataExplorer.contribution';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { DataExplorerViewletViewsContribution, OpenDataExplorerViewletAction, VIEWLET_ID } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet'; import { DataExplorerViewletViewsContribution, OpenDataExplorerViewletAction } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
@@ -16,7 +15,6 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { DataExplorerContainerExtensionHandler } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerExtensionPoint'; import { DataExplorerContainerExtensionHandler } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerExtensionPoint';
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).setDefaultViewletId(VIEWLET_ID);
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench); const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(DataExplorerViewletViewsContribution, LifecyclePhase.Starting); workbenchRegistry.registerWorkbenchContribution(DataExplorerViewletViewsContribution, LifecyclePhase.Starting);
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
@@ -159,4 +159,4 @@ export const VIEW_CONTAINER = Registry.as<IViewContainersRegistry>(ViewContainer
icon: 'dataExplorer', icon: 'dataExplorer',
order: 0, order: 0,
storageId: `${VIEWLET_ID}.state` storageId: `${VIEWLET_ID}.state`
}, ViewContainerLocation.Sidebar); }, ViewContainerLocation.Sidebar, true);
@@ -31,9 +31,10 @@ import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/t
import { UNSAVED_GROUP_ID, mssqlProviderName } from 'sql/platform/connection/common/constants'; import { UNSAVED_GROUP_ID, mssqlProviderName } from 'sql/platform/connection/common/constants';
import { $ } from 'vs/base/browser/dom'; import { $ } from 'vs/base/browser/dom';
import { OEManageConnectionAction } from 'sql/workbench/contrib/dashboard/browser/dashboardActions'; import { OEManageConnectionAction } from 'sql/workbench/contrib/dashboard/browser/dashboardActions';
import { IViewsService, IView } from 'vs/workbench/common/views'; import { IViewsService, IView, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views';
import { ConsoleLogService } from 'vs/platform/log/common/log'; import { ConsoleLogService } from 'vs/platform/log/common/log';
import { IProgressIndicator } from 'vs/platform/progress/common/progress'; import { IProgressIndicator } from 'vs/platform/progress/common/progress';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
suite('SQL Connection Tree Action tests', () => { suite('SQL Connection Tree Action tests', () => {
let errorMessageService: TypeMoq.Mock<TestErrorMessageService>; let errorMessageService: TypeMoq.Mock<TestErrorMessageService>;
@@ -110,6 +111,22 @@ suite('SQL Connection Tree Action tests', () => {
}); });
const viewsService = new class implements IViewsService { const viewsService = new class implements IViewsService {
getViewProgressIndicator(id: string): IProgressIndicator {
throw new Error('Method not implemented.');
}
onDidChangeViewContainerVisibility: Event<{ id: string; visible: boolean; location: ViewContainerLocation; }>;
isViewContainerVisible(id: string): boolean {
throw new Error('Method not implemented.');
}
openViewContainer(id: string, focus?: boolean): Promise<IPaneComposite> {
throw new Error('Method not implemented.');
}
closeViewContainer(id: string): void {
throw new Error('Method not implemented.');
}
getVisibleViewContainer(location: ViewContainerLocation): ViewContainer {
throw new Error('Method not implemented.');
}
getProgressIndicator(id: string): IProgressIndicator { getProgressIndicator(id: string): IProgressIndicator {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
@@ -230,10 +230,10 @@ export class BreadcrumbsWidget {
for (let i = 0; i < this._nodes.length; i++) { for (let i = 0; i < this._nodes.length; i++) {
const node = this._nodes[i]; const node = this._nodes[i];
if (i !== nth) { if (i !== nth) {
dom.removeClass(node, 'focused'); node.classList.remove('focused');
} else { } else {
this._focusedItemIdx = i; this._focusedItemIdx = i;
dom.addClass(node, 'focused'); node.classList.add('focused');
node.focus(); node.focus();
} }
} }
@@ -274,10 +274,10 @@ export class BreadcrumbsWidget {
for (let i = 0; i < this._nodes.length; i++) { for (let i = 0; i < this._nodes.length; i++) {
const node = this._nodes[i]; const node = this._nodes[i];
if (i !== nth) { if (i !== nth) {
dom.removeClass(node, 'selected'); node.classList.remove('selected');
} else { } else {
this._selectedItemIdx = i; this._selectedItemIdx = i;
dom.addClass(node, 'selected'); node.classList.add('selected');
} }
} }
this._onDidSelectItem.fire({ type: 'select', item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx], payload }); this._onDidSelectItem.fire({ type: 'select', item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx], payload });
+4
View File
@@ -10,6 +10,10 @@ export namespace Iterable {
return _empty; return _empty;
} }
export function* single<T>(element: T): Iterable<T> {
yield element;
}
export function from<T>(iterable: Iterable<T> | undefined | null): Iterable<T> { export function from<T>(iterable: Iterable<T> | undefined | null): Iterable<T> {
return iterable || _empty; return iterable || _empty;
} }
+64 -37
View File
@@ -481,7 +481,9 @@ export class TernarySearchTree<K, V> {
} }
} }
export class ResourceMap<T> { export class ResourceMap<T> implements Map<URI, T> {
readonly [Symbol.toStringTag] = 'ResourceMap';
protected readonly map: Map<string, T>; protected readonly map: Map<string, T>;
protected readonly ignoreCase?: boolean; protected readonly ignoreCase?: boolean;
@@ -491,8 +493,9 @@ export class ResourceMap<T> {
this.ignoreCase = false; // in the future this should be an uri-comparator this.ignoreCase = false; // in the future this should be an uri-comparator
} }
set(resource: URI, value: T): void { set(resource: URI, value: T): this {
this.map.set(this.toKey(resource), value); this.map.set(this.toKey(resource), value);
return this;
} }
get(resource: URI): T | undefined { get(resource: URI): T | undefined {
@@ -515,12 +518,35 @@ export class ResourceMap<T> {
return this.map.delete(this.toKey(resource)); return this.map.delete(this.toKey(resource));
} }
forEach(clb: (value: T, key: URI) => void): void { forEach(clb: (value: T, key: URI, map: Map<URI, T>) => void, thisArg?: any): void {
this.map.forEach((value, index) => clb(value, URI.parse(index))); if (typeof thisArg !== 'undefined') {
clb = clb.bind(thisArg);
}
for (let [index, value] of this.map) {
clb(value, URI.parse(index), <any>this);
}
} }
values(): T[] { values(): IterableIterator<T> {
return values(this.map); return this.map.values();
}
*keys(): IterableIterator<URI> {
for (let key of this.map.keys()) {
yield URI.parse(key);
}
}
*entries(): IterableIterator<[URI, T]> {
for (let tuple of this.map.entries()) {
yield [URI.parse(tuple[0]), tuple[1]];
}
}
*[Symbol.iterator](): IterableIterator<[URI, T]> {
for (let item of this.map) {
yield [URI.parse(item[0]), item[1]];
}
} }
private toKey(resource: URI): string { private toKey(resource: URI): string {
@@ -532,10 +558,6 @@ export class ResourceMap<T> {
return key; return key;
} }
keys(): URI[] {
return keys(this.map).map(k => URI.parse(k));
}
clone(): ResourceMap<T> { clone(): ResourceMap<T> {
const resourceMap = new ResourceMap<T>(); const resourceMap = new ResourceMap<T>();
@@ -558,7 +580,9 @@ export const enum Touch {
AsNew = 2 AsNew = 2
} }
export class LinkedMap<K, V> { export class LinkedMap<K, V> implements Map<K, V>{
readonly [Symbol.toStringTag] = 'LinkedMap';
private _map: Map<K, Item<K, V>>; private _map: Map<K, Item<K, V>>;
private _head: Item<K, V> | undefined; private _head: Item<K, V> | undefined;
@@ -610,7 +634,7 @@ export class LinkedMap<K, V> {
return item.value; return item.value;
} }
set(key: K, value: V, touch: Touch = Touch.None): void { set(key: K, value: V, touch: Touch = Touch.None): this {
let item = this._map.get(key); let item = this._map.get(key);
if (item) { if (item) {
item.value = value; item.value = value;
@@ -636,6 +660,7 @@ export class LinkedMap<K, V> {
this._map.set(key, item); this._map.set(key, item);
this._size++; this._size++;
} }
return this;
} }
delete(key: K): boolean { delete(key: K): boolean {
@@ -679,29 +704,8 @@ export class LinkedMap<K, V> {
} }
} }
values(): V[] {
const result: V[] = [];
let current = this._head;
while (current) {
result.push(current.value);
current = current.next;
}
return result;
}
keys(): K[] {
const result: K[] = [];
let current = this._head;
while (current) {
result.push(current.key);
current = current.next;
}
return result;
}
/* VS Code / Monaco editor runs on es5 which has no Symbol.iterator
keys(): IterableIterator<K> { keys(): IterableIterator<K> {
const current = this._head; let current = this._head;
const iterator: IterableIterator<K> = { const iterator: IterableIterator<K> = {
[Symbol.iterator]() { [Symbol.iterator]() {
return iterator; return iterator;
@@ -720,7 +724,7 @@ export class LinkedMap<K, V> {
} }
values(): IterableIterator<V> { values(): IterableIterator<V> {
const current = this._head; let current = this._head;
const iterator: IterableIterator<V> = { const iterator: IterableIterator<V> = {
[Symbol.iterator]() { [Symbol.iterator]() {
return iterator; return iterator;
@@ -737,7 +741,29 @@ export class LinkedMap<K, V> {
}; };
return iterator; return iterator;
} }
*/
entries(): IterableIterator<[K, V]> {
let current = this._head;
const iterator: IterableIterator<[K, V]> = {
[Symbol.iterator]() {
return iterator;
},
next(): IteratorResult<[K, V]> {
if (current) {
const result: IteratorResult<[K, V]> = { value: [current.key, current.value], done: false };
current = current.next;
return result;
} else {
return { value: undefined, done: true };
}
}
};
return iterator;
}
[Symbol.iterator](): IterableIterator<[K, V]> {
return this.entries();
}
protected trimOld(newSize: number) { protected trimOld(newSize: number) {
if (newSize >= this.size) { if (newSize >= this.size) {
@@ -939,9 +965,10 @@ export class LRUCache<K, V> extends LinkedMap<K, V> {
return super.get(key, Touch.None); return super.get(key, Touch.None);
} }
set(key: K, value: V): void { set(key: K, value: V): this {
super.set(key, value, Touch.AsNew); super.set(key, value, Touch.AsNew);
this.checkTrim(); this.checkTrim();
return this;
} }
private checkTrim() { private checkTrim() {
@@ -274,8 +274,10 @@ class QuickInput extends Disposable implements IQuickInput {
return; return;
} }
const title = this.getTitle(); const title = this.getTitle();
if (this.ui.title.textContent !== title) { if (title && this.ui.title.textContent !== title) {
this.ui.title.textContent = title; this.ui.title.textContent = title;
} else if (!title && this.ui.title.innerHTML !== '&nbsp;') {
this.ui.title.innerHTML = '&nbsp;';
} }
const description = this.getDescription(); const description = this.getDescription();
if (this.ui.description.textContent !== description) { if (this.ui.description.textContent !== description) {
+37 -32
View File
@@ -13,8 +13,8 @@ suite('Map', () => {
let map = new LinkedMap<string, string>(); let map = new LinkedMap<string, string>();
map.set('ak', 'av'); map.set('ak', 'av');
map.set('bk', 'bv'); map.set('bk', 'bv');
assert.deepStrictEqual(map.keys(), ['ak', 'bk']); assert.deepStrictEqual([...map.keys()], ['ak', 'bk']);
assert.deepStrictEqual(map.values(), ['av', 'bv']); assert.deepStrictEqual([...map.values()], ['av', 'bv']);
assert.equal(map.first, 'av'); assert.equal(map.first, 'av');
assert.equal(map.last, 'bv'); assert.equal(map.last, 'bv');
}); });
@@ -23,16 +23,16 @@ suite('Map', () => {
let map = new LinkedMap<string, string>(); let map = new LinkedMap<string, string>();
map.set('ak', 'av'); map.set('ak', 'av');
map.set('ak', 'av', Touch.AsOld); map.set('ak', 'av', Touch.AsOld);
assert.deepStrictEqual(map.keys(), ['ak']); assert.deepStrictEqual([...map.keys()], ['ak']);
assert.deepStrictEqual(map.values(), ['av']); assert.deepStrictEqual([...map.values()], ['av']);
}); });
test('LinkedMap - Touch New one', () => { test('LinkedMap - Touch New one', () => {
let map = new LinkedMap<string, string>(); let map = new LinkedMap<string, string>();
map.set('ak', 'av'); map.set('ak', 'av');
map.set('ak', 'av', Touch.AsNew); map.set('ak', 'av', Touch.AsNew);
assert.deepStrictEqual(map.keys(), ['ak']); assert.deepStrictEqual([...map.keys()], ['ak']);
assert.deepStrictEqual(map.values(), ['av']); assert.deepStrictEqual([...map.values()], ['av']);
}); });
test('LinkedMap - Touch Old two', () => { test('LinkedMap - Touch Old two', () => {
@@ -40,8 +40,8 @@ suite('Map', () => {
map.set('ak', 'av'); map.set('ak', 'av');
map.set('bk', 'bv'); map.set('bk', 'bv');
map.set('bk', 'bv', Touch.AsOld); map.set('bk', 'bv', Touch.AsOld);
assert.deepStrictEqual(map.keys(), ['bk', 'ak']); assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
assert.deepStrictEqual(map.values(), ['bv', 'av']); assert.deepStrictEqual([...map.values()], ['bv', 'av']);
}); });
test('LinkedMap - Touch New two', () => { test('LinkedMap - Touch New two', () => {
@@ -49,8 +49,8 @@ suite('Map', () => {
map.set('ak', 'av'); map.set('ak', 'av');
map.set('bk', 'bv'); map.set('bk', 'bv');
map.set('ak', 'av', Touch.AsNew); map.set('ak', 'av', Touch.AsNew);
assert.deepStrictEqual(map.keys(), ['bk', 'ak']); assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
assert.deepStrictEqual(map.values(), ['bv', 'av']); assert.deepStrictEqual([...map.values()], ['bv', 'av']);
}); });
test('LinkedMap - Touch Old from middle', () => { test('LinkedMap - Touch Old from middle', () => {
@@ -59,8 +59,8 @@ suite('Map', () => {
map.set('bk', 'bv'); map.set('bk', 'bv');
map.set('ck', 'cv'); map.set('ck', 'cv');
map.set('bk', 'bv', Touch.AsOld); map.set('bk', 'bv', Touch.AsOld);
assert.deepStrictEqual(map.keys(), ['bk', 'ak', 'ck']); assert.deepStrictEqual([...map.keys()], ['bk', 'ak', 'ck']);
assert.deepStrictEqual(map.values(), ['bv', 'av', 'cv']); assert.deepStrictEqual([...map.values()], ['bv', 'av', 'cv']);
}); });
test('LinkedMap - Touch New from middle', () => { test('LinkedMap - Touch New from middle', () => {
@@ -69,8 +69,8 @@ suite('Map', () => {
map.set('bk', 'bv'); map.set('bk', 'bv');
map.set('ck', 'cv'); map.set('ck', 'cv');
map.set('bk', 'bv', Touch.AsNew); map.set('bk', 'bv', Touch.AsNew);
assert.deepStrictEqual(map.keys(), ['ak', 'ck', 'bk']); assert.deepStrictEqual([...map.keys()], ['ak', 'ck', 'bk']);
assert.deepStrictEqual(map.values(), ['av', 'cv', 'bv']); assert.deepStrictEqual([...map.values()], ['av', 'cv', 'bv']);
}); });
test('LinkedMap - basics', function () { test('LinkedMap - basics', function () {
@@ -136,13 +136,15 @@ suite('Map', () => {
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
cache.set(6, 6); cache.set(6, 6);
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
assert.deepStrictEqual(cache.keys(), [2, 3, 4, 5, 6]); assert.deepStrictEqual([...cache.keys()], [2, 3, 4, 5, 6]);
cache.set(7, 7); cache.set(7, 7);
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
assert.deepStrictEqual(cache.keys(), [3, 4, 5, 6, 7]); assert.deepStrictEqual([...cache.keys()], [3, 4, 5, 6, 7]);
let values: number[] = []; let values: number[] = [];
[3, 4, 5, 6, 7].forEach(key => values.push(cache.get(key)!)); [3, 4, 5, 6, 7].forEach(key => values.push(cache.get(key)!));
assert.deepStrictEqual(values, [3, 4, 5, 6, 7]); assert.deepStrictEqual(values, [3, 4, 5, 6, 7]);
assert.deepEqual([...cache.entries()], [[3, 3], [4, 4], [5, 5], [6, 6], [7, 7]]);
}); });
test('LinkedMap - LRU Cache get', () => { test('LinkedMap - LRU Cache get', () => {
@@ -150,11 +152,11 @@ suite('Map', () => {
[1, 2, 3, 4, 5].forEach(value => cache.set(value, value)); [1, 2, 3, 4, 5].forEach(value => cache.set(value, value));
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
assert.deepStrictEqual(cache.keys(), [1, 2, 3, 4, 5]); assert.deepStrictEqual([...cache.keys()], [1, 2, 3, 4, 5]);
cache.get(3); cache.get(3);
assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]); assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
cache.peek(4); cache.peek(4);
assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]); assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
let values: number[] = []; let values: number[] = [];
[1, 2, 3, 4, 5].forEach(key => values.push(cache.get(key)!)); [1, 2, 3, 4, 5].forEach(key => values.push(cache.get(key)!));
assert.deepStrictEqual(values, [1, 2, 3, 4, 5]); assert.deepStrictEqual(values, [1, 2, 3, 4, 5]);
@@ -169,7 +171,7 @@ suite('Map', () => {
assert.strictEqual(cache.size, 10); assert.strictEqual(cache.size, 10);
cache.limit = 5; cache.limit = 5;
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
assert.deepStrictEqual(cache.keys(), [6, 7, 8, 9, 10]); assert.deepStrictEqual([...cache.keys()], [6, 7, 8, 9, 10]);
cache.limit = 20; cache.limit = 20;
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
for (let i = 11; i <= 20; i++) { for (let i = 11; i <= 20; i++) {
@@ -181,7 +183,7 @@ suite('Map', () => {
values.push(cache.get(i)!); values.push(cache.get(i)!);
assert.strictEqual(cache.get(i), i); assert.strictEqual(cache.get(i), i);
} }
assert.deepStrictEqual(cache.values(), values); assert.deepStrictEqual([...cache.values()], values);
}); });
test('LinkedMap - LRU Cache limit with ratio', () => { test('LinkedMap - LRU Cache limit with ratio', () => {
@@ -193,11 +195,11 @@ suite('Map', () => {
assert.strictEqual(cache.size, 10); assert.strictEqual(cache.size, 10);
cache.set(11, 11); cache.set(11, 11);
assert.strictEqual(cache.size, 5); assert.strictEqual(cache.size, 5);
assert.deepStrictEqual(cache.keys(), [7, 8, 9, 10, 11]); assert.deepStrictEqual([...cache.keys()], [7, 8, 9, 10, 11]);
let values: number[] = []; let values: number[] = [];
cache.keys().forEach(key => values.push(cache.get(key)!)); [...cache.keys()].forEach(key => values.push(cache.get(key)!));
assert.deepStrictEqual(values, [7, 8, 9, 10, 11]); assert.deepStrictEqual(values, [7, 8, 9, 10, 11]);
assert.deepStrictEqual(cache.values(), values); assert.deepStrictEqual([...cache.values()], values);
}); });
test('LinkedMap - toJSON / fromJSON', () => { test('LinkedMap - toJSON / fromJSON', () => {
@@ -237,7 +239,7 @@ suite('Map', () => {
map.delete('1'); map.delete('1');
assert.equal(map.get('1'), undefined); assert.equal(map.get('1'), undefined);
assert.equal(map.size, 0); assert.equal(map.size, 0);
assert.equal(map.keys().length, 0); assert.equal([...map.keys()].length, 0);
}); });
test('LinkedMap - delete Head', function () { test('LinkedMap - delete Head', function () {
@@ -251,8 +253,8 @@ suite('Map', () => {
map.delete('1'); map.delete('1');
assert.equal(map.get('2'), 2); assert.equal(map.get('2'), 2);
assert.equal(map.size, 1); assert.equal(map.size, 1);
assert.equal(map.keys().length, 1); assert.equal([...map.keys()].length, 1);
assert.equal(map.keys()[0], 2); assert.equal([...map.keys()][0], 2);
}); });
test('LinkedMap - delete Tail', function () { test('LinkedMap - delete Tail', function () {
@@ -266,8 +268,8 @@ suite('Map', () => {
map.delete('2'); map.delete('2');
assert.equal(map.get('1'), 1); assert.equal(map.get('1'), 1);
assert.equal(map.size, 1); assert.equal(map.size, 1);
assert.equal(map.keys().length, 1); assert.equal([...map.keys()].length, 1);
assert.equal(map.keys()[0], 1); assert.equal([...map.keys()][0], 1);
}); });
@@ -656,18 +658,21 @@ suite('Map', () => {
assert.equal(map.size, 0); assert.equal(map.size, 0);
map.set(resource1, 1); let res = map.set(resource1, 1);
assert.ok(res === map);
map.set(resource2, '2'); map.set(resource2, '2');
map.set(resource3, true); map.set(resource3, true);
const values = map.values(); const values = [...map.values()];
assert.equal(values[0], 1); assert.equal(values[0], 1);
assert.equal(values[1], '2'); assert.equal(values[1], '2');
assert.equal(values[2], true); assert.equal(values[2], true);
let counter = 0; let counter = 0;
map.forEach(value => { map.forEach((value, key, mapObj) => {
assert.equal(value, values[counter++]); assert.equal(value, values[counter++]);
assert.ok(URI.isUri(key));
assert.ok(map === mapObj);
}); });
const obj = Object.create(null); const obj = Object.create(null);
+2 -2
View File
@@ -502,7 +502,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
} }
private onWindowError(error: WindowError): void { private onWindowError(error: WindowError): void {
this.logService.error(error === WindowError.CRASHED ? '[VS Code]: render process crashed!' : '[VS Code]: detected unresponsive'); this.logService.error(error === WindowError.CRASHED ? '[VS Code]: renderer process crashed!' : '[VS Code]: detected unresponsive');
// If we run extension tests from CLI, showing a dialog is not // If we run extension tests from CLI, showing a dialog is not
// very helpful in this case. Rather, we bring down the test run // very helpful in this case. Rather, we bring down the test run
@@ -937,7 +937,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// Multi Montior (fullscreen): try to find the previously used display // Multi Montior (fullscreen): try to find the previously used display
if (state.display && state.mode === WindowMode.Fullscreen) { if (state.display && state.mode === WindowMode.Fullscreen) {
const display = displays.filter(d => d.id === state.display)[0]; const display = displays.find(d => d.id === state.display);
if (display && typeof display.bounds?.x === 'number' && typeof display.bounds?.y === 'number') { if (display && typeof display.bounds?.x === 'number' && typeof display.bounds?.y === 'number') {
this.logService.trace('window#validateWindowState: restoring fullscreen to previous display'); this.logService.trace('window#validateWindowState: restoring fullscreen to previous display');
+1 -1
View File
@@ -216,7 +216,7 @@ export class Main {
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) }; const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User); const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
const newer = installedExtensions.filter(local => areSameExtensions(extensionIdentifier, local.identifier) && semver.gt(local.manifest.version, manifest.version))[0]; const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && semver.gt(local.manifest.version, manifest.version));
if (newer && !force) { if (newer && !force) {
console.log(localize('forceDowngrade', "A newer version of extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.", newer.identifier.id, newer.manifest.version, manifest.version)); console.log(localize('forceDowngrade', "A newer version of extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.", newer.identifier.id, newer.manifest.version, manifest.version));
+14 -2
View File
@@ -156,12 +156,13 @@ export class StableEditorScrollState {
visiblePositionScrollDelta = editor.getScrollTop() - visiblePositionScrollTop; visiblePositionScrollDelta = editor.getScrollTop() - visiblePositionScrollTop;
} }
} }
return new StableEditorScrollState(visiblePosition, visiblePositionScrollDelta); return new StableEditorScrollState(visiblePosition, visiblePositionScrollDelta, editor.getPosition());
} }
constructor( constructor(
private readonly _visiblePosition: Position | null, private readonly _visiblePosition: Position | null,
private readonly _visiblePositionScrollDelta: number private readonly _visiblePositionScrollDelta: number,
private readonly _cursorPosition: Position | null
) { ) {
} }
@@ -171,4 +172,15 @@ export class StableEditorScrollState {
editor.setScrollTop(visiblePositionScrollTop + this._visiblePositionScrollDelta); editor.setScrollTop(visiblePositionScrollTop + this._visiblePositionScrollDelta);
} }
} }
public restoreRelativeVerticalPositionOfCursor(editor: ICodeEditor): void {
const currentCursorPosition = editor.getPosition();
if (!this._cursorPosition || !currentCursorPosition) {
return;
}
const offset = editor.getTopForLineNumber(currentCursorPosition.lineNumber) - editor.getTopForLineNumber(this._cursorPosition.lineNumber);
editor.setScrollTop(editor.getScrollTop() + offset);
}
} }
@@ -21,6 +21,8 @@ import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { withNullAsUndefined, assertType } from 'vs/base/common/types'; import { withNullAsUndefined, assertType } from 'vs/base/common/types';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
export type ServicesAccessor = InstantiationServicesAccessor; export type ServicesAccessor = InstantiationServicesAccessor;
export type IEditorContributionCtor = IConstructorSignature1<ICodeEditor, IEditorContribution>; export type IEditorContributionCtor = IConstructorSignature1<ICodeEditor, IEditorContribution>;
@@ -48,6 +50,7 @@ export interface ICommandMenuOptions {
order: number; order: number;
when?: ContextKeyExpression; when?: ContextKeyExpression;
title: string; title: string;
icon?: ThemeIcon
} }
export interface ICommandOptions { export interface ICommandOptions {
id: string; id: string;
@@ -118,6 +121,7 @@ export abstract class Command {
command: { command: {
id: this.id, id: this.id,
title: item.title, title: item.title,
icon: item.icon
// precondition: this.precondition // precondition: this.precondition
}, },
when: item.when, when: item.when,
@@ -1804,7 +1804,7 @@ export class EditorModeContext extends Disposable {
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService); this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService); this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService);
this._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(_contextKeyService); this._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(_contextKeyService); this._isInWalkThrough = EditorContextKeys.isInWalkThroughSnippet.bindTo(_contextKeyService);
const update = () => this._update(); const update = () => this._update();
+8 -1
View File
@@ -32,10 +32,17 @@ export namespace EditorContextKeys {
export const hasSingleSelection = hasMultipleSelections.toNegated(); export const hasSingleSelection = hasMultipleSelections.toNegated();
export const tabMovesFocus = new RawContextKey<boolean>('editorTabMovesFocus', false); export const tabMovesFocus = new RawContextKey<boolean>('editorTabMovesFocus', false);
export const tabDoesNotMoveFocus = tabMovesFocus.toNegated(); export const tabDoesNotMoveFocus = tabMovesFocus.toNegated();
export const isInEmbeddedEditor = new RawContextKey<boolean>('isInEmbeddedEditor', false); export const isInWalkThroughSnippet = new RawContextKey<boolean>('isInEmbeddedEditor', false);
export const canUndo = new RawContextKey<boolean>('canUndo', false); export const canUndo = new RawContextKey<boolean>('canUndo', false);
export const canRedo = new RawContextKey<boolean>('canRedo', false); export const canRedo = new RawContextKey<boolean>('canRedo', false);
/**
* A context key that is set when an editor is part of a larger editor, like notebooks or
* (future) a diff editor
*/
export const inCompositeEditor = new RawContextKey<boolean>('inCompositeEditor', undefined);
export const notInCompositeEditor = inCompositeEditor.toNegated();
// -- mode context keys // -- mode context keys
export const languageId = new RawContextKey<string>('editorLangId', ''); export const languageId = new RawContextKey<string>('editorLangId', '');
export const hasCompletionItemProvider = new RawContextKey<boolean>('editorHasCompletionItemProvider', false); export const hasCompletionItemProvider = new RawContextKey<boolean>('editorHasCompletionItemProvider', false);
+9 -2
View File
@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
@@ -1276,7 +1277,8 @@ export class ValidAnnotatedEditOperation implements IIdentifiedSingleEditOperati
/** /**
* @internal * @internal
*/ */
export interface ITextBuffer { export interface IReadonlyTextBuffer {
onDidChangeContent: Event<void>;
equals(other: ITextBuffer): boolean; equals(other: ITextBuffer): boolean;
mightContainRTL(): boolean; mightContainRTL(): boolean;
mightContainNonBasicASCII(): boolean; mightContainNonBasicASCII(): boolean;
@@ -1299,10 +1301,15 @@ export interface ITextBuffer {
getLineLength(lineNumber: number): number; getLineLength(lineNumber: number): number;
getLineFirstNonWhitespaceColumn(lineNumber: number): number; getLineFirstNonWhitespaceColumn(lineNumber: number): number;
getLineLastNonWhitespaceColumn(lineNumber: number): number; getLineLastNonWhitespaceColumn(lineNumber: number): number;
findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[];
}
/**
* @internal
*/
export interface ITextBuffer extends IReadonlyTextBuffer {
setEOL(newEOL: '\r\n' | '\n'): void; setEOL(newEOL: '\r\n' | '\n'): void;
applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult; applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult;
findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[];
} }
/** /**
@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import * as strings from 'vs/base/common/strings'; import * as strings from 'vs/base/common/strings';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range'; import { Range } from 'vs/editor/common/core/range';
@@ -11,6 +12,7 @@ import { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTex
import { SearchData } from 'vs/editor/common/model/textModelSearch'; import { SearchData } from 'vs/editor/common/model/textModelSearch';
import { countEOL, StringEOL } from 'vs/editor/common/model/tokensStore'; import { countEOL, StringEOL } from 'vs/editor/common/model/tokensStore';
import { TextChange } from 'vs/editor/common/model/textChange'; import { TextChange } from 'vs/editor/common/model/textChange';
import { IDisposable } from 'vs/base/common/lifecycle';
export interface IValidatedEditOperation { export interface IValidatedEditOperation {
sortIndex: number; sortIndex: number;
@@ -30,18 +32,24 @@ export interface IReverseSingleEditOperation extends IValidEditOperation {
sortIndex: number; sortIndex: number;
} }
export class PieceTreeTextBuffer implements ITextBuffer { export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
private readonly _pieceTree: PieceTreeBase; private readonly _pieceTree: PieceTreeBase;
private readonly _BOM: string; private readonly _BOM: string;
private _mightContainRTL: boolean; private _mightContainRTL: boolean;
private _mightContainNonBasicASCII: boolean; private _mightContainNonBasicASCII: boolean;
private readonly _onDidChangeContent: Emitter<void> = new Emitter<void>();
public readonly onDidChangeContent: Event<void> = this._onDidChangeContent.event;
constructor(chunks: StringBuffer[], BOM: string, eol: '\r\n' | '\n', containsRTL: boolean, isBasicASCII: boolean, eolNormalized: boolean) { constructor(chunks: StringBuffer[], BOM: string, eol: '\r\n' | '\n', containsRTL: boolean, isBasicASCII: boolean, eolNormalized: boolean) {
this._BOM = BOM; this._BOM = BOM;
this._mightContainNonBasicASCII = !isBasicASCII; this._mightContainNonBasicASCII = !isBasicASCII;
this._mightContainRTL = containsRTL; this._mightContainRTL = containsRTL;
this._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized); this._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized);
} }
dispose(): void {
this._onDidChangeContent.dispose();
}
// #region TextBuffer // #region TextBuffer
public equals(other: ITextBuffer): boolean { public equals(other: ITextBuffer): boolean {
@@ -360,6 +368,8 @@ export class PieceTreeTextBuffer implements ITextBuffer {
} }
} }
this._onDidChangeContent.fire();
return new ApplyEditsResult( return new ApplyEditsResult(
reverseOperations, reverseOperations,
contentChanges, contentChanges,
+1 -1
View File
@@ -608,7 +608,7 @@ export interface CompletionItemProvider {
* *
* The editor will only resolve a completion item once. * The editor will only resolve a completion item once.
*/ */
resolveCompletionItem?(model: model.ITextModel, position: Position, item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>; resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>;
} }
export interface CodeAction { export interface CodeAction {
@@ -18,6 +18,7 @@ import { Schemas } from 'vs/base/common/network';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { withUndefinedAsNull } from 'vs/base/common/types'; import { withUndefinedAsNull } from 'vs/base/common/types';
import { minimapWarning, minimapError } from 'vs/platform/theme/common/colorRegistry'; import { minimapWarning, minimapError } from 'vs/platform/theme/common/colorRegistry';
import { Delayer } from 'vs/base/common/async';
function MODEL_ID(resource: URI): string { function MODEL_ID(resource: URI): string {
return resource.toString(); return resource.toString();
@@ -41,13 +42,14 @@ class MarkerDecorations extends Disposable {
return super._register(t); return super._register(t);
} }
public update(markers: IMarker[], newDecorations: IModelDeltaDecoration[]): void { public update(markers: IMarker[], newDecorations: IModelDeltaDecoration[]): boolean {
const oldIds = keys(this._markersData); const oldIds = keys(this._markersData);
this._markersData.clear(); this._markersData.clear();
const ids = this.model.deltaDecorations(oldIds, newDecorations); const ids = this.model.deltaDecorations(oldIds, newDecorations);
for (let index = 0; index < ids.length; index++) { for (let index = 0; index < ids.length; index++) {
this._markersData.set(ids[index], markers[index]); this._markersData.set(ids[index], markers[index]);
} }
return oldIds.length !== 0 || ids.length !== 0;
} }
getMarker(decoration: IModelDecoration): IMarker | undefined { getMarker(decoration: IModelDecoration): IMarker | undefined {
@@ -114,7 +116,8 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
private _onModelAdded(model: ITextModel): void { private _onModelAdded(model: ITextModel): void {
const markerDecorations = new MarkerDecorations(model); const markerDecorations = new MarkerDecorations(model);
this._markerDecorations.set(MODEL_ID(model.uri), markerDecorations); this._markerDecorations.set(MODEL_ID(model.uri), markerDecorations);
markerDecorations.register(model.onDidChangeContent(() => this._updateDecorations(markerDecorations))); const delayer = markerDecorations.register(new Delayer(100));
markerDecorations.register(model.onDidChangeContent(() => delayer.trigger(() => this._updateDecorations(markerDecorations))));
this._updateDecorations(markerDecorations); this._updateDecorations(markerDecorations);
} }
@@ -144,9 +147,10 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
options: this._createDecorationOption(marker) options: this._createDecorationOption(marker)
}; };
}); });
markerDecorations.update(markers, newModelDecorations); if (markerDecorations.update(markers, newModelDecorations)) {
this._onDidChangeMarker.fire(markerDecorations.model); this._onDidChangeMarker.fire(markerDecorations.model);
} }
}
private _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range { private _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range {
@@ -29,9 +29,13 @@ export class SemanticTokensProviderStyling {
let metadata: number; let metadata: number;
if (entry) { if (entry) {
metadata = entry.metadata; metadata = entry.metadata;
if (this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace(`SemanticTokensProviderStyling [CACHED] ${tokenTypeIndex} / ${tokenModifierSet}: foreground ${TokenMetadata.getForeground(metadata)}, fontStyle ${TokenMetadata.getFontStyle(metadata).toString(2)}`);
}
} else { } else {
const tokenType = this._legend.tokenTypes[tokenTypeIndex]; let tokenType = this._legend.tokenTypes[tokenTypeIndex];
const tokenModifiers: string[] = []; const tokenModifiers: string[] = [];
if (tokenType) {
let modifierSet = tokenModifierSet; let modifierSet = tokenModifierSet;
for (let modifierIndex = 0; modifierSet > 0 && modifierIndex < this._legend.tokenModifiers.length; modifierIndex++) { for (let modifierIndex = 0; modifierSet > 0 && modifierIndex < this._legend.tokenModifiers.length; modifierIndex++) {
if (modifierSet & 1) { if (modifierSet & 1) {
@@ -39,6 +43,10 @@ export class SemanticTokensProviderStyling {
} }
modifierSet = modifierSet >> 1; modifierSet = modifierSet >> 1;
} }
if (modifierSet > 0 && this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace(`SemanticTokensProviderStyling: unknown token modifier index: ${tokenModifierSet.toString(2)} for legend: ${JSON.stringify(this._legend.tokenModifiers)}`);
tokenModifiers.push('not-in-legend');
}
const tokenStyle = this._themeService.getColorTheme().getTokenStyleMetadata(tokenType, tokenModifiers, languageId.language); const tokenStyle = this._themeService.getColorTheme().getTokenStyleMetadata(tokenType, tokenModifiers, languageId.language);
if (typeof tokenStyle === 'undefined') { if (typeof tokenStyle === 'undefined') {
@@ -66,13 +74,20 @@ export class SemanticTokensProviderStyling {
metadata = SemanticTokensProviderStylingConstants.NO_STYLING; metadata = SemanticTokensProviderStylingConstants.NO_STYLING;
} }
} }
this._hashTable.add(tokenTypeIndex, tokenModifierSet, languageId.id, metadata); } else {
}
if (this._logService.getLevel() === LogLevel.Trace) { if (this._logService.getLevel() === LogLevel.Trace) {
const type = this._legend.tokenTypes[tokenTypeIndex]; this._logService.trace(`SemanticTokensProviderStyling: unknown token type index: ${tokenTypeIndex} for legend: ${JSON.stringify(this._legend.tokenTypes)}`);
const modifiers = tokenModifierSet ? ' ' + this._legend.tokenModifiers.filter((_, i) => tokenModifierSet & (1 << i)).join(' ') : '';
this._logService.trace(`tokenStyleMetadata ${entry ? '[CACHED] ' : ''}${type}${modifiers}: foreground ${TokenMetadata.getForeground(metadata)}, fontStyle ${TokenMetadata.getFontStyle(metadata).toString(2)}`);
} }
metadata = SemanticTokensProviderStylingConstants.NO_STYLING;
tokenType = 'not-in-legend';
}
this._hashTable.add(tokenTypeIndex, tokenModifierSet, languageId.id, metadata);
if (this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace(`SemanticTokensProviderStyling ${tokenTypeIndex} (${tokenType}) / ${tokenModifierSet} (${tokenModifiers.join(' ')}): foreground ${TokenMetadata.getForeground(metadata)}, fontStyle ${TokenMetadata.getFontStyle(metadata).toString(2)}`);
}
}
return metadata; return metadata;
} }
} }
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./codelensWidget'; import 'vs/css!./codelensWidget';
import * as dom from 'vs/base/browser/dom';
import { renderCodicons } from 'vs/base/common/codicons'; import { renderCodicons } from 'vs/base/common/codicons';
import { escape } from 'vs/base/common/strings'; import { escape } from 'vs/base/common/strings';
import { IViewZone, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; import { IViewZone, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser';
@@ -113,7 +112,7 @@ class CodeLensContentWidget implements IContentWidget {
} }
this._domNode.innerHTML = innerHtml; this._domNode.innerHTML = innerHtml;
if (this._isEmpty && animate) { if (this._isEmpty && animate) {
dom.addClass(this._domNode, 'fadein'); this._domNode.classList.add('fadein');
} }
this._isEmpty = false; this._isEmpty = false;
} }
@@ -102,7 +102,7 @@ export class OutlineGroupRenderer implements ITreeRenderer<OutlineGroup, FuzzySc
renderTemplate(container: HTMLElement): OutlineGroupTemplate { renderTemplate(container: HTMLElement): OutlineGroupTemplate {
const labelContainer = dom.$('.outline-element-label'); const labelContainer = dom.$('.outline-element-label');
dom.addClass(container, 'outline-element'); container.classList.add('outline-element');
dom.append(container, labelContainer); dom.append(container, labelContainer);
return new OutlineGroupTemplate(labelContainer, new HighlightedLabel(labelContainer, true)); return new OutlineGroupTemplate(labelContainer, new HighlightedLabel(labelContainer, true));
} }
@@ -129,7 +129,7 @@ export class OutlineElementRenderer implements ITreeRenderer<OutlineElement, Fuz
) { } ) { }
renderTemplate(container: HTMLElement): OutlineElementTemplate { renderTemplate(container: HTMLElement): OutlineElementTemplate {
dom.addClass(container, 'outline-element'); container.classList.add('outline-element');
const iconLabel = new IconLabel(container, { supportHighlights: true }); const iconLabel = new IconLabel(container, { supportHighlights: true });
const iconClass = dom.$('.outline-element-icon'); const iconClass = dom.$('.outline-element-icon');
const decoration = dom.$('.outline-element-decoration'); const decoration = dom.$('.outline-element-decoration');
@@ -184,14 +184,14 @@ export class OutlineElementRenderer implements ITreeRenderer<OutlineElement, Fuz
} else if (count > 0) { } else if (count > 0) {
dom.show(template.decoration); dom.show(template.decoration);
dom.removeClass(template.decoration, 'bubble'); template.decoration.classList.remove('bubble');
template.decoration.innerText = count < 10 ? count.toString() : '+9'; template.decoration.innerText = count < 10 ? count.toString() : '+9';
template.decoration.title = count === 1 ? localize('1.problem', "1 problem in this element") : localize('N.problem', "{0} problems in this element", count); template.decoration.title = count === 1 ? localize('1.problem', "1 problem in this element") : localize('N.problem', "{0} problems in this element", count);
template.decoration.style.setProperty('--outline-element-color', cssColor); template.decoration.style.setProperty('--outline-element-color', cssColor);
} else { } else {
dom.show(template.decoration); dom.show(template.decoration);
dom.addClass(template.decoration, 'bubble'); template.decoration.classList.add('bubble');
template.decoration.innerText = '\uea71'; template.decoration.innerText = '\uea71';
template.decoration.title = localize('deep.problem', "Contains elements with problems"); template.decoration.title = localize('deep.problem', "Contains elements with problems");
template.decoration.style.setProperty('--outline-element-color', cssColor); template.decoration.style.setProperty('--outline-element-color', cssColor);
@@ -213,7 +213,7 @@ class FormatDocumentAction extends EditorAction {
id: 'editor.action.formatDocument', id: 'editor.action.formatDocument',
label: nls.localize('formatDocument.label', "Format Document"), label: nls.localize('formatDocument.label', "Format Document"),
alias: 'Format Document', alias: 'Format Document',
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider), precondition: ContextKeyExpr.and(EditorContextKeys.notInCompositeEditor, EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider),
kbOpts: { kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentFormattingProvider), kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentFormattingProvider),
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,
+28 -22
View File
@@ -15,7 +15,6 @@ import { Range } from 'vs/editor/common/core/range';
import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { registerEditorAction, registerEditorContribution, ServicesAccessor, IActionOptions, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions'; import { registerEditorAction, registerEditorContribution, ServicesAccessor, IActionOptions, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { MarkerNavigationWidget } from './gotoErrorWidget'; import { MarkerNavigationWidget } from './gotoErrorWidget';
@@ -24,12 +23,10 @@ import { binarySearch, find } from 'vs/base/common/arrays';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { Action } from 'vs/base/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { isEqual } from 'vs/base/common/resources'; import { isEqual } from 'vs/base/common/resources';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
import { Codicon, registerIcon } from 'vs/base/common/codicons'; import { Codicon, registerIcon } from 'vs/base/common/codicons';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
class MarkerModel { class MarkerModel {
@@ -192,9 +189,6 @@ class MarkerModel {
} }
} }
const markerNavigationNextIcon = registerIcon('marker-navigation-next', Codicon.chevronDown);
const markerNavigationPreviousIcon = registerIcon('marker-navigation-previous', Codicon.chevronUp);
export class MarkerController implements IEditorContribution { export class MarkerController implements IEditorContribution {
public static readonly ID = 'editor.contrib.markerController'; public static readonly ID = 'editor.contrib.markerController';
@@ -213,10 +207,8 @@ export class MarkerController implements IEditorContribution {
editor: ICodeEditor, editor: ICodeEditor,
@IMarkerService private readonly _markerService: IMarkerService, @IMarkerService private readonly _markerService: IMarkerService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService, @IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IThemeService private readonly _themeService: IThemeService,
@ICodeEditorService private readonly _editorService: ICodeEditorService, @ICodeEditorService private readonly _editorService: ICodeEditorService,
@IKeybindingService private readonly _keybindingService: IKeybindingService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@IOpenerService private readonly _openerService: IOpenerService
) { ) {
this._editor = editor; this._editor = editor;
this._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService); this._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService);
@@ -244,21 +236,13 @@ export class MarkerController implements IEditorContribution {
this._model = new MarkerModel(this._editor, markers); this._model = new MarkerModel(this._editor, markers);
this._markerService.onMarkerChanged(this._onMarkerChanged, this, this._disposeOnClose); this._markerService.onMarkerChanged(this._onMarkerChanged, this, this._disposeOnClose);
const prevMarkerKeybinding = this._keybindingService.lookupKeybinding(PrevMarkerAction.ID); this._widget = this._instantiationService.createInstance(MarkerNavigationWidget, this._editor);
const nextMarkerKeybinding = this._keybindingService.lookupKeybinding(NextMarkerAction.ID);
const actions = [
new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem ' + markerNavigationNextIcon.classNames, this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }),
new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem ' + markerNavigationPreviousIcon.classNames, this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } })
];
this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService, this._openerService);
this._widgetVisible.set(true); this._widgetVisible.set(true);
this._widget.onDidClose(() => this.closeMarkersNavigation(), this, this._disposeOnClose); this._widget.onDidClose(() => this.closeMarkersNavigation(), this, this._disposeOnClose);
this._disposeOnClose.add(this._model); this._disposeOnClose.add(this._model);
this._disposeOnClose.add(this._widget); this._disposeOnClose.add(this._widget);
for (const action of actions) {
this._disposeOnClose.add(action);
}
this._disposeOnClose.add(this._widget.onDidSelectRelatedInformation(related => { this._disposeOnClose.add(this._widget.onDidSelectRelatedInformation(related => {
this._editorService.openCodeEditor({ this._editorService.openCodeEditor({
resource: related.resource, resource: related.resource,
@@ -431,7 +415,18 @@ export class NextMarkerAction extends MarkerNavigationAction {
label: NextMarkerAction.LABEL, label: NextMarkerAction.LABEL,
alias: 'Go to Next Problem (Error, Warning, Info)', alias: 'Go to Next Problem (Error, Warning, Info)',
precondition: undefined, precondition: undefined,
kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib } kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.Alt | KeyCode.F8,
weight: KeybindingWeight.EditorContrib
},
menuOpts: {
menuId: MarkerNavigationWidget.TitleMenu,
title: NextMarkerAction.LABEL,
icon: registerIcon('marker-navigation-next', Codicon.chevronDown),
group: 'navigation',
order: 1
}
}); });
} }
} }
@@ -445,7 +440,18 @@ class PrevMarkerAction extends MarkerNavigationAction {
label: PrevMarkerAction.LABEL, label: PrevMarkerAction.LABEL,
alias: 'Go to Previous Problem (Error, Warning, Info)', alias: 'Go to Previous Problem (Error, Warning, Info)',
precondition: undefined, precondition: undefined,
kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib } kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F8,
weight: KeybindingWeight.EditorContrib
},
menuOpts: {
menuId: MarkerNavigationWidget.TitleMenu,
title: NextMarkerAction.LABEL,
icon: registerIcon('marker-navigation-previous', Codicon.chevronUp),
group: 'navigation',
order: 2
}
}); });
} }
} }
@@ -27,6 +27,10 @@ import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/action
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
class MessageWidget { class MessageWidget {
@@ -224,6 +228,8 @@ class MessageWidget {
export class MarkerNavigationWidget extends PeekViewWidget { export class MarkerNavigationWidget extends PeekViewWidget {
static readonly TitleMenu = new MenuId('gotoErrorTitleMenu');
private _parentContainer!: HTMLElement; private _parentContainer!: HTMLElement;
private _container!: HTMLElement; private _container!: HTMLElement;
private _icon!: HTMLElement; private _icon!: HTMLElement;
@@ -238,9 +244,11 @@ export class MarkerNavigationWidget extends PeekViewWidget {
constructor( constructor(
editor: ICodeEditor, editor: ICodeEditor,
private readonly actions: ReadonlyArray<IAction>, @IThemeService private readonly _themeService: IThemeService,
private readonly _themeService: IThemeService, @IOpenerService private readonly _openerService: IOpenerService,
private readonly _openerService: IOpenerService @IMenuService private readonly _menuService: IMenuService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) { ) {
super(editor, { showArrow: true, showFrame: true, isAccessible: true }); super(editor, { showArrow: true, showFrame: true, isAccessible: true });
this._severity = MarkerSeverity.Warning; this._severity = MarkerSeverity.Warning;
@@ -288,7 +296,11 @@ export class MarkerNavigationWidget extends PeekViewWidget {
protected _fillHead(container: HTMLElement): void { protected _fillHead(container: HTMLElement): void {
super._fillHead(container); super._fillHead(container);
this._actionbarWidget!.push(this.actions, { label: false, icon: true, index: 0 }); const actions: IAction[] = [];
const menu = this._menuService.createMenu(MarkerNavigationWidget.TitleMenu, this._contextKeyService);
createAndFillInActionBarActions(menu, undefined, actions);
this._actionbarWidget!.push(actions, { label: false, icon: true, index: 0 });
menu.dispose();
} }
protected _fillTitleIcon(container: HTMLElement): void { protected _fillTitleIcon(container: HTMLElement): void {
@@ -297,7 +309,8 @@ export class MarkerNavigationWidget extends PeekViewWidget {
protected _getActionBarOptions(): IActionBarOptions { protected _getActionBarOptions(): IActionBarOptions {
return { return {
orientation: ActionsOrientation.HORIZONTAL orientation: ActionsOrientation.HORIZONTAL,
actionViewItemProvider: action => action instanceof MenuItemAction ? this._instantiationService.createInstance(MenuEntryActionViewItem, action) : undefined
}; };
} }
@@ -240,7 +240,7 @@ registerEditorAction(class GoToDefinitionAction extends DefinitionAction {
alias: 'Go to Definition', alias: 'Go to Definition',
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasDefinitionProvider, EditorContextKeys.hasDefinitionProvider,
EditorContextKeys.isInEmbeddedEditor.toNegated()), EditorContextKeys.isInWalkThroughSnippet.toNegated()),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
primary: goToDefinitionKb, primary: goToDefinitionKb,
@@ -276,7 +276,7 @@ registerEditorAction(class OpenDefinitionToSideAction extends DefinitionAction {
alias: 'Open Definition to the Side', alias: 'Open Definition to the Side',
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasDefinitionProvider, EditorContextKeys.hasDefinitionProvider,
EditorContextKeys.isInEmbeddedEditor.toNegated()), EditorContextKeys.isInWalkThroughSnippet.toNegated()),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, goToDefinitionKb), primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, goToDefinitionKb),
@@ -303,7 +303,7 @@ registerEditorAction(class PeekDefinitionAction extends DefinitionAction {
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasDefinitionProvider, EditorContextKeys.hasDefinitionProvider,
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
@@ -361,7 +361,7 @@ registerEditorAction(class GoToDeclarationAction extends DeclarationAction {
alias: 'Go to Declaration', alias: 'Go to Declaration',
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasDeclarationProvider, EditorContextKeys.hasDeclarationProvider,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
contextMenuOpts: { contextMenuOpts: {
group: 'navigation', group: 'navigation',
@@ -396,7 +396,7 @@ registerEditorAction(class PeekDeclarationAction extends DeclarationAction {
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasDeclarationProvider, EditorContextKeys.hasDeclarationProvider,
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
contextMenuOpts: { contextMenuOpts: {
menuId: MenuId.EditorContextPeek, menuId: MenuId.EditorContextPeek,
@@ -447,7 +447,7 @@ registerEditorAction(class GoToTypeDefinitionAction extends TypeDefinitionAction
alias: 'Go to Type Definition', alias: 'Go to Type Definition',
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasTypeDefinitionProvider, EditorContextKeys.hasTypeDefinitionProvider,
EditorContextKeys.isInEmbeddedEditor.toNegated()), EditorContextKeys.isInWalkThroughSnippet.toNegated()),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
primary: 0, primary: 0,
@@ -483,7 +483,7 @@ registerEditorAction(class PeekTypeDefinitionAction extends TypeDefinitionAction
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasTypeDefinitionProvider, EditorContextKeys.hasTypeDefinitionProvider,
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
contextMenuOpts: { contextMenuOpts: {
menuId: MenuId.EditorContextPeek, menuId: MenuId.EditorContextPeek,
@@ -534,7 +534,7 @@ registerEditorAction(class GoToImplementationAction extends ImplementationAction
alias: 'Go to Implementations', alias: 'Go to Implementations',
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasImplementationProvider, EditorContextKeys.hasImplementationProvider,
EditorContextKeys.isInEmbeddedEditor.toNegated()), EditorContextKeys.isInWalkThroughSnippet.toNegated()),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
primary: KeyMod.CtrlCmd | KeyCode.F12, primary: KeyMod.CtrlCmd | KeyCode.F12,
@@ -570,7 +570,7 @@ registerEditorAction(class PeekImplementationAction extends ImplementationAction
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasImplementationProvider, EditorContextKeys.hasImplementationProvider,
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
@@ -621,7 +621,7 @@ registerEditorAction(class GoToReferencesAction extends ReferencesAction {
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasReferenceProvider, EditorContextKeys.hasReferenceProvider,
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: EditorContextKeys.editorTextFocus,
@@ -660,7 +660,7 @@ registerEditorAction(class PeekReferencesAction extends ReferencesAction {
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
EditorContextKeys.hasReferenceProvider, EditorContextKeys.hasReferenceProvider,
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
contextMenuOpts: { contextMenuOpts: {
menuId: MenuId.EditorContextPeek, menuId: MenuId.EditorContextPeek,
@@ -693,7 +693,7 @@ class GenericGoToLocationAction extends SymbolNavigationAction {
alias: 'Go To Any Symbol', alias: 'Go To Any Symbol',
precondition: ContextKeyExpr.and( precondition: ContextKeyExpr.and(
PeekContext.notInPeekEditor, PeekContext.notInPeekEditor,
EditorContextKeys.isInEmbeddedEditor.toNegated() EditorContextKeys.isInWalkThroughSnippet.toNegated()
), ),
}); });
} }
@@ -119,7 +119,7 @@ class FileReferencesTemplate extends Disposable {
) { ) {
super(); super();
const parent = document.createElement('div'); const parent = document.createElement('div');
dom.addClass(parent, 'reference-file'); parent.classList.add('reference-file');
this.file = this._register(new IconLabel(parent, { supportHighlights: true })); this.file = this._register(new IconLabel(parent, { supportHighlights: true }));
this.badge = new CountBadge(dom.append(parent, dom.$('.count'))); this.badge = new CountBadge(dom.append(parent, dom.$('.count')));
@@ -184,10 +184,10 @@ class OneReferenceTemplate {
// we have score, then render the score // we have score, then render the score
const { value, highlight } = preview; const { value, highlight } = preview;
if (score && !FuzzyScore.isDefault(score)) { if (score && !FuzzyScore.isDefault(score)) {
dom.toggleClass(this.label.element, 'referenceMatch', false); this.label.element.classList.toggle('referenceMatch', false);
this.label.set(value, createMatches(score)); this.label.set(value, createMatches(score));
} else { } else {
dom.toggleClass(this.label.element, 'referenceMatch', true); this.label.element.classList.toggle('referenceMatch', true);
this.label.set(value, [highlight]); this.label.set(value, [highlight]);
} }
} }
@@ -465,7 +465,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
})); }));
// make sure things are rendered // make sure things are rendered
dom.addClass(this.container!, 'results-loaded'); this.container!.classList.add('results-loaded');
dom.show(this._treeContainer); dom.show(this._treeContainer);
dom.show(this._previewContainer); dom.show(this._previewContainer);
this._splitView.layout(this._dim.width); this._splitView.layout(this._dim.width);
+2 -1
View File
@@ -30,7 +30,8 @@
} }
.monaco-editor-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr { .monaco-editor-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
min-width: 100%; /* This is a strange rule but it avoids https://github.com/microsoft/vscode/issues/96795, just 100vw on its own caused the actual hover width to increase */
min-width: calc(100% + 100vw);
} }
.monaco-editor-hover p, .monaco-editor-hover p,
@@ -15,7 +15,6 @@ import { inputBackground, inputBorder, inputForeground, widgetShadow, editorWidg
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { toggleClass } from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
export const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey<boolean>('renameInputVisible', false); export const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey<boolean>('renameInputVisible', false);
@@ -152,7 +151,7 @@ export class RenameInputField implements IContentWidget {
getInput(where: IRange, value: string, selectionStart: number, selectionEnd: number, supportPreview: boolean, token: CancellationToken): Promise<RenameInputFieldResult | boolean> { getInput(where: IRange, value: string, selectionStart: number, selectionEnd: number, supportPreview: boolean, token: CancellationToken): Promise<RenameInputFieldResult | boolean> {
toggleClass(this._domNode!, 'preview', supportPreview); this._domNode!.classList.toggle('preview', supportPreview);
this._position = new Position(where.startLineNumber, where.startColumn); this._position = new Position(where.startLineNumber, where.startColumn);
this._input!.value = value; this._input!.value = value;
@@ -5,7 +5,6 @@
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { repeat } from 'vs/base/common/strings';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { Range } from 'vs/editor/common/core/range'; import { Range } from 'vs/editor/common/core/range';
@@ -191,7 +190,7 @@ export class SnippetController2 implements IEditorContribution {
insertText: option.value, insertText: option.value,
// insertText: `\${1|${after.concat(before).join(',')}|}$0`, // insertText: `\${1|${after.concat(before).join(',')}|}$0`,
// snippetType: 'textmate', // snippetType: 'textmate',
sortText: repeat('a', i + 1), sortText: 'a'.repeat(i + 1),
range: Range.fromPositions(this._editor.getPosition()!, this._editor.getPosition()!.delta(0, first.value.length)) range: Range.fromPositions(this._editor.getPosition()!, this._editor.getPosition()!.delta(0, first.value.length))
}; };
})); }));
@@ -101,7 +101,7 @@ export class CompletionModel {
} }
adopt(except: Set<CompletionItemProvider>): CompletionItem[] { adopt(except: Set<CompletionItemProvider>): CompletionItem[] {
let res = new Array<CompletionItem>(); let res: CompletionItem[] = [];
for (let i = 0; i < this._items.length;) { for (let i = 0; i < this._items.length;) {
if (!except.has(this._items[i].provider)) { if (!except.has(this._items[i].provider)) {
res.push(this._items[i]); res.push(this._items[i]);
@@ -151,6 +151,10 @@ export class CompletionModel {
const item = source[i]; const item = source[i];
if (item.isInvalid) {
continue; // SKIP invalid items
}
// collect those supports that signaled having // collect those supports that signaled having
// an incomplete result // an incomplete result
if (item.container.incomplete) { if (item.container.incomplete) {
+92 -85
View File
@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { first } from 'vs/base/common/async';
import { onUnexpectedExternalError, canceled, isPromiseCanceledError } from 'vs/base/common/errors'; import { onUnexpectedExternalError, canceled, isPromiseCanceledError } from 'vs/base/common/errors';
import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model'; import { ITextModel } from 'vs/editor/common/model';
@@ -34,12 +33,6 @@ export class CompletionItem {
_brand!: 'ISuggestionItem'; _brand!: 'ISuggestionItem';
private static readonly _defaultResolve = () => Promise.resolve();
readonly resolve: (token: CancellationToken) => Promise<void>;
isResolved: boolean = false;
// //
readonly editStart: IPosition; readonly editStart: IPosition;
readonly editInsertEnd: IPosition; readonly editInsertEnd: IPosition;
@@ -53,6 +46,9 @@ export class CompletionItem {
readonly sortTextLow?: string; readonly sortTextLow?: string;
readonly filterTextLow?: string; readonly filterTextLow?: string;
// validation
readonly isInvalid: boolean = false;
// sorting, filtering // sorting, filtering
score: FuzzyScore = FuzzyScore.Default; score: FuzzyScore = FuzzyScore.Default;
distance: number = 0; distance: number = 0;
@@ -73,6 +69,9 @@ export class CompletionItem {
// ensure lower-variants (perf) // ensure lower-variants (perf)
this.labelLow = this.textLabel.toLowerCase(); this.labelLow = this.textLabel.toLowerCase();
// validate label
this.isInvalid = !this.textLabel;
this.sortTextLow = completion.sortText && completion.sortText.toLowerCase(); this.sortTextLow = completion.sortText && completion.sortText.toLowerCase();
this.filterTextLow = completion.filterText && completion.filterText.toLowerCase(); this.filterTextLow = completion.filterText && completion.filterText.toLowerCase();
@@ -81,42 +80,53 @@ export class CompletionItem {
this.editStart = new Position(completion.range.startLineNumber, completion.range.startColumn); this.editStart = new Position(completion.range.startLineNumber, completion.range.startColumn);
this.editInsertEnd = new Position(completion.range.endLineNumber, completion.range.endColumn); this.editInsertEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);
this.editReplaceEnd = new Position(completion.range.endLineNumber, completion.range.endColumn); this.editReplaceEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);
// validate range
this.isInvalid = this.isInvalid
|| Range.spansMultipleLines(completion.range) || completion.range.startLineNumber !== position.lineNumber;
} else { } else {
this.editStart = new Position(completion.range.insert.startLineNumber, completion.range.insert.startColumn); this.editStart = new Position(completion.range.insert.startLineNumber, completion.range.insert.startColumn);
this.editInsertEnd = new Position(completion.range.insert.endLineNumber, completion.range.insert.endColumn); this.editInsertEnd = new Position(completion.range.insert.endLineNumber, completion.range.insert.endColumn);
this.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn); this.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn);
// validate ranges
this.isInvalid = this.isInvalid
|| Range.spansMultipleLines(completion.range.insert) || Range.spansMultipleLines(completion.range.replace)
|| completion.range.insert.startLineNumber !== position.lineNumber || completion.range.replace.startLineNumber !== position.lineNumber
|| Range.compareRangesUsingStarts(completion.range.insert, completion.range.replace) !== 0;
} }
// create the suggestion resolver // create the suggestion resolver
const { resolveCompletionItem } = provider; if (typeof provider.resolveCompletionItem !== 'function') {
if (typeof resolveCompletionItem !== 'function') { this._resolveCache = Promise.resolve();
this.resolve = CompletionItem._defaultResolve; }
this.isResolved = true; }
} else {
let cached: Promise<void> | undefined; // resolving
this.resolve = (token) => { get isResolved() {
if (!cached) { return Boolean(this._resolveCache);
cached = Promise.resolve(resolveCompletionItem.call(provider, model, Position.lift(position), completion, token)).then(value => { }
Object.assign(completion, value);
this.isResolved = true; private _resolveCache?: Promise<void>;
async resolve(token: CancellationToken) {
if (!this._resolveCache) {
const sub = token.onCancellationRequested(() => {
this._resolveCache = undefined;
});
this._resolveCache = Promise.resolve(this.provider.resolveCompletionItem!(this.completion, token)).then(value => {
Object.assign(this.completion, value);
sub.dispose();
}, err => { }, err => {
if (isPromiseCanceledError(err)) { if (isPromiseCanceledError(err)) {
// the IPC queue will reject the request with the // the IPC queue will reject the request with the
// cancellation error -> reset cached // cancellation error -> reset cached
cached = undefined; this._resolveCache = undefined;
}
});
token.onCancellationRequested(() => {
if (!this.isResolved) {
// cancellation after the request has been
// dispatched -> reset cache
cached = undefined;
} }
}); });
} }
return cached; return this._resolveCache;
};
}
} }
} }
@@ -147,7 +157,7 @@ export function setSnippetSuggestSupport(support: modes.CompletionItemProvider):
return old; return old;
} }
export function provideSuggestionItems( export async function provideSuggestionItems(
model: ITextModel, model: ITextModel,
position: Position, position: Position,
options: CompletionOptions = CompletionOptions.default, options: CompletionOptions = CompletionOptions.default,
@@ -155,89 +165,86 @@ export function provideSuggestionItems(
token: CancellationToken = CancellationToken.None token: CancellationToken = CancellationToken.None
): Promise<CompletionItem[]> { ): Promise<CompletionItem[]> {
const word = model.getWordAtPosition(position); // const t1 = Date.now();
const defaultReplaceRange = word ? new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : Range.fromPositions(position);
const defaultInsertRange = defaultReplaceRange.setEndPosition(position.lineNumber, position.column);
// const wordUntil = model.getWordUntilPosition(position);
// const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn);
position = position.clone(); position = position.clone();
// get provider groups, always add snippet suggestion provider const word = model.getWordAtPosition(position);
const supports = modes.CompletionProviderRegistry.orderedGroups(model); const defaultReplaceRange = word ? new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : Range.fromPositions(position);
const defaultRange = { replace: defaultReplaceRange, insert: defaultReplaceRange.setEndPosition(position.lineNumber, position.column) };
// add snippets provider unless turned off const result: CompletionItem[] = [];
if (!options.kindFilter.has(modes.CompletionItemKind.Snippet) && _snippetSuggestSupport) {
supports.unshift([_snippetSuggestSupport]);
}
const allSuggestions: CompletionItem[] = [];
const disposables = new DisposableStore(); const disposables = new DisposableStore();
let hasResult = false;
// add suggestions from contributed providers - providers are ordered in groups of const onCompletionList = (provider: modes.CompletionItemProvider, container: modes.CompletionList | null | undefined) => {
// equal score and once a group produces a result the process stops if (!container) {
const factory = supports.map(supports => () => { return;
// for each support in the group ask for suggestions
return Promise.all(supports.map(provider => {
if (options.providerFilter.size > 0 && !options.providerFilter.has(provider)) {
return undefined;
} }
return Promise.resolve(provider.provideCompletionItems(model, position, context, token)).then(container => {
const len = allSuggestions.length;
if (container) {
for (let suggestion of container.suggestions || []) { for (let suggestion of container.suggestions || []) {
if (!options.kindFilter.has(suggestion.kind)) { if (!options.kindFilter.has(suggestion.kind)) {
// fill in default range when missing // fill in default range when missing
if (!suggestion.range) { if (!suggestion.range) {
suggestion.range = { insert: defaultInsertRange, replace: defaultReplaceRange }; suggestion.range = defaultRange;
} }
// fill in default sortText when missing // fill in default sortText when missing
if (!suggestion.sortText) { if (!suggestion.sortText) {
suggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name; suggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;
} }
result.push(new CompletionItem(position, suggestion, container, provider, model));
allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model));
} }
} }
if (isDisposable(container)) { if (isDisposable(container)) {
disposables.add(container); disposables.add(container);
} }
} };
if (len !== allSuggestions.length && provider !== _snippetSuggestSupport) { // ask for snippets in parallel to asking "real" providers. Only do something if configured to
hasResult = true; // do so - no snippet filter, no special-providers-only request
const snippetCompletions = new Promise<void>((resolve, reject) => {
if (!_snippetSuggestSupport || options.kindFilter.has(modes.CompletionItemKind.Snippet)) {
resolve();
} }
if (options.providerFilter.size > 0 && !options.providerFilter.has(_snippetSuggestSupport)) {
}, onUnexpectedExternalError); resolve();
})); }
Promise.resolve(_snippetSuggestSupport.provideCompletionItems(model, position, context, token)).then(list => {
onCompletionList(_snippetSuggestSupport, list);
resolve();
}, reject);
}); });
const result = first(factory, () => { // add suggestions from contributed providers - providers are ordered in groups of
// stop on result or cancellation // equal score and once a group produces a result the process stops
return hasResult || token.isCancellationRequested; // get provider groups, always add snippet suggestion provider
}).then(() => { for (let providerGroup of modes.CompletionProviderRegistry.orderedGroups(model)) {
// for each support in the group ask for suggestions
let lenBefore = result.length;
await Promise.all(providerGroup.map(async provider => {
if (options.providerFilter.size > 0 && !options.providerFilter.has(provider)) {
return;
}
try {
const list = await provider.provideCompletionItems(model, position, context, token);
onCompletionList(provider, list);
} catch (err) {
onUnexpectedExternalError(err);
}
}));
if (lenBefore !== result.length || token.isCancellationRequested) {
break;
}
}
await snippetCompletions;
if (token.isCancellationRequested) { if (token.isCancellationRequested) {
disposables.dispose(); disposables.dispose();
return Promise.reject<any>(canceled()); return Promise.reject<any>(canceled());
} }
return allSuggestions.sort(getSuggestionComparator(options.snippetSortOrder)); // console.log(`${result.length} items AFTER ${Date.now() - t1}ms`);
}); return result.sort(getSuggestionComparator(options.snippetSortOrder));
// result.then(items => {
// console.log(model.getWordUntilPosition(position), items.map(item => `${item.suggestion.label}, type=${item.suggestion.type}, incomplete?${item.container.incomplete}, overwriteBefore=${item.suggestion.overwriteBefore}`));
// return items;
// }, err => {
// console.warn(model.getWordUntilPosition(position), err);
// });
return result;
} }
@@ -8,6 +8,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { KeyCode, KeyMod, SimpleKeybinding } from 'vs/base/common/keyCodes'; import { KeyCode, KeyMod, SimpleKeybinding } from 'vs/base/common/keyCodes';
import { dispose, IDisposable, DisposableStore, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { dispose, IDisposable, DisposableStore, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { StableEditorScrollState } from 'vs/editor/browser/core/editorState';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { EditOperation } from 'vs/editor/common/core/editOperation'; import { EditOperation } from 'vs/editor/common/core/editOperation';
@@ -273,6 +274,8 @@ export class SuggestController implements IEditorContribution {
// keep item in memory // keep item in memory
this._memoryService.memorize(model, this.editor.getPosition(), item); this._memoryService.memorize(model, this.editor.getPosition(), item);
const scrollState = StableEditorScrollState.capture(this.editor);
if (Array.isArray(suggestion.additionalTextEdits)) { if (Array.isArray(suggestion.additionalTextEdits)) {
this.editor.executeEdits('suggestController.additionalTextEdits', suggestion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); this.editor.executeEdits('suggestController.additionalTextEdits', suggestion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));
} }
@@ -290,6 +293,8 @@ export class SuggestController implements IEditorContribution {
adjustWhitespace: !(suggestion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace) adjustWhitespace: !(suggestion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace)
}); });
scrollState.restoreRelativeVerticalPositionOfCursor(this.editor);
if (!(flags & InsertFlags.NoAfterUndoStop)) { if (!(flags & InsertFlags.NoAfterUndoStop)) {
this.editor.pushUndoStop(); this.editor.pushUndoStop();
} }
+27 -29
View File
@@ -13,7 +13,7 @@ import * as strings from 'vs/base/common/strings';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener, addStandardDisposableListener, addClasses } from 'vs/base/browser/dom'; import { append, $, hide, show, getDomNodePagePosition, addDisposableListener, addStandardDisposableListener, addClasses } from 'vs/base/browser/dom';
import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent, IListGestureEvent } from 'vs/base/browser/ui/list/list'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent, IListGestureEvent } from 'vs/base/browser/ui/list/list';
import { List } from 'vs/base/browser/ui/list/listWidget'; import { List } from 'vs/base/browser/ui/list/listWidget';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
@@ -139,7 +139,7 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
data.disposables = new DisposableStore(); data.disposables = new DisposableStore();
data.root = container; data.root = container;
addClass(data.root, 'show-file-icons'); data.root.classList.add('show-file-icons');
data.icon = append(container, $('.icon')); data.icon = append(container, $('.icon'));
data.colorspan = append(data.icon, $('span.colorspan')); data.colorspan = append(data.icon, $('span.colorspan'));
@@ -245,16 +245,16 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
data.parametersLabel.textContent = ''; data.parametersLabel.textContent = '';
data.qualifierLabel.textContent = ''; data.qualifierLabel.textContent = '';
data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
addClass(data.root, 'string-label'); data.root.classList.add('string-label');
} else { } else {
data.parametersLabel.textContent = (suggestion.label.parameters || '').replace(/\n.*$/m, ''); data.parametersLabel.textContent = (suggestion.label.parameters || '').replace(/\n.*$/m, '');
data.qualifierLabel.textContent = (suggestion.label.qualifier || '').replace(/\n.*$/m, ''); data.qualifierLabel.textContent = (suggestion.label.qualifier || '').replace(/\n.*$/m, '');
data.detailsLabel.textContent = (suggestion.label.type || '').replace(/\n.*$/m, ''); data.detailsLabel.textContent = (suggestion.label.type || '').replace(/\n.*$/m, '');
removeClass(data.root, 'string-label'); data.root.classList.remove('string-label');
} }
if (canExpandCompletionItem(element)) { if (canExpandCompletionItem(element)) {
addClass(data.right, 'can-expand-details'); data.right.classList.add('can-expand-details');
show(data.readMore); show(data.readMore);
data.readMore.onmousedown = e => { data.readMore.onmousedown = e => {
e.stopPropagation(); e.stopPropagation();
@@ -266,7 +266,7 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
this.widget.toggleDetails(); this.widget.toggleDetails();
}; };
} else { } else {
removeClass(data.right, 'can-expand-details'); data.right.classList.remove('can-expand-details');
hide(data.readMore); hide(data.readMore);
data.readMore.onmousedown = null; data.readMore.onmousedown = null;
data.readMore.onclick = null; data.readMore.onclick = null;
@@ -363,15 +363,15 @@ class SuggestionDetails {
if (!explainMode && !canExpandCompletionItem(item)) { if (!explainMode && !canExpandCompletionItem(item)) {
this.type.textContent = ''; this.type.textContent = '';
this.docs.textContent = ''; this.docs.textContent = '';
addClass(this.el, 'no-docs'); this.el.classList.add('no-docs');
return; return;
} }
removeClass(this.el, 'no-docs'); this.el.classList.remove('no-docs');
if (typeof documentation === 'string') { if (typeof documentation === 'string') {
removeClass(this.docs, 'markdown-docs'); this.docs.classList.remove('markdown-docs');
this.docs.textContent = documentation; this.docs.textContent = documentation;
} else { } else {
addClass(this.docs, 'markdown-docs'); this.docs.classList.add('markdown-docs');
this.docs.innerHTML = ''; this.docs.innerHTML = '';
const renderedContents = this.markdownRenderer.render(documentation); const renderedContents = this.markdownRenderer.render(documentation);
this.renderDisposeable = renderedContents; this.renderDisposeable = renderedContents;
@@ -554,7 +554,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this.messageElement = append(this.element, $('.message')); this.messageElement = append(this.element, $('.message'));
this.listElement = append(this.element, $('.tree')); this.listElement = append(this.element, $('.tree'));
const applyStatusBarStyle = () => toggleClass(this.element, 'with-status-bar', this.editor.getOption(EditorOption.suggest).statusBar.visible); const applyStatusBarStyle = () => this.element.classList.toggle('with-status-bar', this.editor.getOption(EditorOption.suggest).statusBar.visible);
applyStatusBarStyle(); applyStatusBarStyle();
this.statusBarElement = append(this.element, $('.suggest-status-bar')); this.statusBarElement = append(this.element, $('.suggest-status-bar'));
@@ -598,7 +598,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this.details = instantiationService.createInstance(SuggestionDetails, this.element, this, this.editor, markdownRenderer, kbToggleDetails); this.details = instantiationService.createInstance(SuggestionDetails, this.element, this, this.editor, markdownRenderer, kbToggleDetails);
const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons); const applyIconStyle = () => this.element.classList.toggle('no-icons', !this.editor.getOption(EditorOption.suggest).showIcons);
applyIconStyle(); applyIconStyle();
let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, kbToggleDetails); let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, kbToggleDetails);
@@ -797,7 +797,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
if (this.expandDocsSettingFromStorage()) { if (this.expandDocsSettingFromStorage()) {
this.showDetails(false); this.showDetails(false);
} else { } else {
removeClass(this.element, 'docs-side'); this.element.classList.remove('docs-side');
} }
this.editor.setAriaOptions({ activeDescendant: getAriaId(index) }); this.editor.setAriaOptions({ activeDescendant: getAriaId(index) });
@@ -821,7 +821,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
const stateChanged = this.state !== state; const stateChanged = this.state !== state;
this.state = state; this.state = state;
toggleClass(this.element, 'frozen', state === State.Frozen); this.element.classList.toggle('frozen', state === State.Frozen);
switch (state) { switch (state) {
case State.Hidden: case State.Hidden:
@@ -837,7 +837,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this.messageElement.textContent = SuggestWidget.LOADING_MESSAGE; this.messageElement.textContent = SuggestWidget.LOADING_MESSAGE;
hide(this.listElement, this.details.element, this.statusBarElement); hide(this.listElement, this.details.element, this.statusBarElement);
show(this.messageElement); show(this.messageElement);
removeClass(this.element, 'docs-side'); this.element.classList.remove('docs-side');
this.show(); this.show();
this.focusedItem = null; this.focusedItem = null;
break; break;
@@ -845,7 +845,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this.messageElement.textContent = SuggestWidget.NO_SUGGESTIONS_MESSAGE; this.messageElement.textContent = SuggestWidget.NO_SUGGESTIONS_MESSAGE;
hide(this.listElement, this.details.element, this.statusBarElement); hide(this.listElement, this.details.element, this.statusBarElement);
show(this.messageElement); show(this.messageElement);
removeClass(this.element, 'docs-side'); this.element.classList.remove('docs-side');
this.show(); this.show();
this.focusedItem = null; this.focusedItem = null;
break; break;
@@ -1072,8 +1072,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this.ctxSuggestWidgetDetailsVisible.set(false); this.ctxSuggestWidgetDetailsVisible.set(false);
this.updateExpandDocsSetting(false); this.updateExpandDocsSetting(false);
hide(this.details.element); hide(this.details.element);
removeClass(this.element, 'docs-side'); this.element.classList.remove('docs-side', 'doc-below');
removeClass(this.element, 'docs-below');
this.editor.layoutContentWidget(this); this.editor.layoutContentWidget(this);
this.telemetryService.publicLog2('suggestWidget:collapseDetails'); this.telemetryService.publicLog2('suggestWidget:collapseDetails');
} else { } else {
@@ -1132,7 +1131,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
this.ctxSuggestWidgetVisible.set(true); this.ctxSuggestWidgetVisible.set(true);
this.showTimeout.cancelAndSet(() => { this.showTimeout.cancelAndSet(() => {
addClass(this.element, 'visible'); this.element.classList.add('visible');
this.onDidShowEmitter.fire(this); this.onDidShowEmitter.fire(this);
}, 100); }, 100);
} }
@@ -1140,7 +1139,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
private hide(): void { private hide(): void {
this.ctxSuggestWidgetVisible.reset(); this.ctxSuggestWidgetVisible.reset();
this.ctxSuggestWidgetMultipleSuggestions.reset(); this.ctxSuggestWidgetMultipleSuggestions.reset();
removeClass(this.element, 'visible'); this.element.classList.remove('visible');
} }
hideWidget(): void { hideWidget(): void {
@@ -1225,15 +1224,15 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
if (widgetX < cursorX - this.listWidth) { if (widgetX < cursorX - this.listWidth) {
// Widget is too far to the left of cursor, swap list and docs // Widget is too far to the left of cursor, swap list and docs
addClass(this.element, 'list-right'); this.element.classList.add('list-right');
} else { } else {
removeClass(this.element, 'list-right'); this.element.classList.remove('list-right');
} }
// Compare top of the cursor (cursorY - lineheight) with widgetTop to determine if // Compare top of the cursor (cursorY - lineheight) with widgetTop to determine if
// margin-top needs to be applied on list to make it appear right above the cursor // margin-top needs to be applied on list to make it appear right above the cursor
// Cannot compare cursorY directly as it may be a few decimals off due to zoooming // Cannot compare cursorY directly as it may be a few decimals off due to zoooming
if (hasClass(this.element, 'docs-side') if (this.element.classList.contains('docs-side')
&& cursorY - lineHeight > widgetY && cursorY - lineHeight > widgetY
&& this.details.element.offsetHeight > this.listElement.offsetHeight) { && this.details.element.offsetHeight > this.listElement.offsetHeight) {
@@ -1248,18 +1247,17 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
*/ */
private expandSideOrBelow() { private expandSideOrBelow() {
if (!canExpandCompletionItem(this.focusedItem) && this.firstFocusInCurrentList) { if (!canExpandCompletionItem(this.focusedItem) && this.firstFocusInCurrentList) {
removeClass(this.element, 'docs-side'); this.element.classList.remove('docs-side', 'docs-below');
removeClass(this.element, 'docs-below');
return; return;
} }
let matches = this.element.style.maxWidth!.match(/(\d+)px/); let matches = this.element.style.maxWidth!.match(/(\d+)px/);
if (!matches || Number(matches[1]) < this.maxWidgetWidth) { if (!matches || Number(matches[1]) < this.maxWidgetWidth) {
addClass(this.element, 'docs-below'); this.element.classList.add('docs-below');
removeClass(this.element, 'docs-side'); this.element.classList.remove('docs-side');
} else if (canExpandCompletionItem(this.focusedItem)) { } else if (canExpandCompletionItem(this.focusedItem)) {
addClass(this.element, 'docs-side'); this.element.classList.add('docs-side');
removeClass(this.element, 'docs-below'); this.element.classList.remove('docs-below');
} }
} }
@@ -757,7 +757,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
dispose() { disposeB += 1; } dispose() { disposeB += 1; }
}; };
}, },
resolveCompletionItem(doc, pos, item) { resolveCompletionItem(item) {
return item; return item;
}, },
})); }));
@@ -214,13 +214,13 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
create(): void { create(): void {
dom.addClass(this.domNode, 'zone-widget'); this.domNode.classList.add('zone-widget');
if (this.options.className) { if (this.options.className) {
dom.addClass(this.domNode, this.options.className); this.domNode.classList.add(this.options.className);
} }
this.container = document.createElement('div'); this.container = document.createElement('div');
dom.addClass(this.container, 'zone-widget-container'); this.container.classList.add('zone-widget-container');
this.domNode.appendChild(this.container); this.domNode.appendChild(this.container);
if (this.options.showArrow) { if (this.options.showArrow) {
this._arrow = new Arrow(this.editor); this._arrow = new Arrow(this.editor);
+1 -1
View File
@@ -5590,7 +5590,7 @@ declare namespace monaco.languages {
* *
* The editor will only resolve a completion item once. * The editor will only resolve a completion item once.
*/ */
resolveCompletionItem?(model: editor.ITextModel, position: Position, item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>; resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>;
} }
export interface CodeAction { export interface CodeAction {
+74 -39
View File
@@ -9,11 +9,13 @@ import { IConstructorSignature2, createDecorator, BrandedService, ServicesAccess
import { IKeybindings, KeybindingsRegistry, IKeybindingRule } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IKeybindings, KeybindingsRegistry, IKeybindingRule } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { UriDto } from 'vs/base/common/types'; import { UriDto } from 'vs/base/common/types';
import { Iterable } from 'vs/base/common/iterator';
import { LinkedList } from 'vs/base/common/linkedList';
export interface ILocalizedString { export interface ILocalizedString {
value: string; value: string;
@@ -159,33 +161,51 @@ export interface IMenuService {
export type ICommandsMap = Map<string, ICommandAction>; export type ICommandsMap = Map<string, ICommandAction>;
export interface IMenuRegistryChangeEvent {
has(id: MenuId): boolean;
}
export interface IMenuRegistry { export interface IMenuRegistry {
readonly onDidChangeMenu: Event<IMenuRegistryChangeEvent>;
addCommands(newCommands: Iterable<ICommandAction>): IDisposable;
addCommand(userCommand: ICommandAction): IDisposable; addCommand(userCommand: ICommandAction): IDisposable;
getCommand(id: string): ICommandAction | undefined; getCommand(id: string): ICommandAction | undefined;
getCommands(): ICommandsMap; getCommands(): ICommandsMap;
appendMenuItems(items: Iterable<{ id: MenuId, item: IMenuItem | ISubmenuItem }>): IDisposable;
appendMenuItem(menu: MenuId, item: IMenuItem | ISubmenuItem): IDisposable; appendMenuItem(menu: MenuId, item: IMenuItem | ISubmenuItem): IDisposable;
getMenuItems(loc: MenuId): Array<IMenuItem | ISubmenuItem>; getMenuItems(loc: MenuId): Array<IMenuItem | ISubmenuItem>;
readonly onDidChangeMenu: Event<MenuId>;
} }
export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry { export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {
private readonly _commands = new Map<string, ICommandAction>(); private readonly _commands = new Map<string, ICommandAction>();
private readonly _menuItems = new Map<MenuId, Array<IMenuItem | ISubmenuItem>>(); private readonly _menuItems = new Map<MenuId, LinkedList<IMenuItem | ISubmenuItem>>();
private readonly _onDidChangeMenu = new Emitter<MenuId>(); private readonly _onDidChangeMenu = new Emitter<IMenuRegistryChangeEvent>();
readonly onDidChangeMenu: Event<MenuId> = this._onDidChangeMenu.event; readonly onDidChangeMenu: Event<IMenuRegistryChangeEvent> = this._onDidChangeMenu.event;
addCommand(command: ICommandAction): IDisposable { addCommand(command: ICommandAction): IDisposable {
this._commands.set(command.id, command); return this.addCommands(Iterable.single(command));
this._onDidChangeMenu.fire(MenuId.CommandPalette);
return {
dispose: () => {
if (this._commands.delete(command.id)) {
this._onDidChangeMenu.fire(MenuId.CommandPalette);
}
} }
private readonly _commandPaletteChangeEvent: IMenuRegistryChangeEvent = {
has: id => id === MenuId.CommandPalette
}; };
addCommands(commands: Iterable<ICommandAction>): IDisposable {
for (const command of commands) {
this._commands.set(command.id, command);
}
this._onDidChangeMenu.fire(this._commandPaletteChangeEvent);
return toDisposable(() => {
let didChange = false;
for (const command of commands) {
didChange = this._commands.delete(command.id) || didChange;
}
if (didChange) {
this._onDidChangeMenu.fire(this._commandPaletteChangeEvent);
}
});
} }
getCommand(id: string): ICommandAction | undefined { getCommand(id: string): ICommandAction | undefined {
@@ -199,28 +219,44 @@ export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {
} }
appendMenuItem(id: MenuId, item: IMenuItem | ISubmenuItem): IDisposable { appendMenuItem(id: MenuId, item: IMenuItem | ISubmenuItem): IDisposable {
let array = this._menuItems.get(id); return this.appendMenuItems(Iterable.single({ id, item }));
if (!array) {
array = [item];
this._menuItems.set(id, array);
} else {
array.push(item);
} }
this._onDidChangeMenu.fire(id);
return { appendMenuItems(items: Iterable<{ id: MenuId, item: IMenuItem | ISubmenuItem }>): IDisposable {
dispose: () => {
const idx = array!.indexOf(item); const changedIds = new Set<MenuId>();
if (idx >= 0) { const toRemove = new LinkedList<Function>();
array!.splice(idx, 1);
this._onDidChangeMenu.fire(id); for (const { id, item } of items) {
let list = this._menuItems.get(id);
if (!list) {
list = new LinkedList();
this._menuItems.set(id, list);
} }
toRemove.push(list.push(item));
changedIds.add(id);
} }
};
this._onDidChangeMenu.fire(changedIds);
return toDisposable(() => {
if (toRemove.size > 0) {
for (let fn of toRemove) {
fn();
}
this._onDidChangeMenu.fire(changedIds);
toRemove.clear();
}
});
} }
getMenuItems(id: MenuId): Array<IMenuItem | ISubmenuItem> { getMenuItems(id: MenuId): Array<IMenuItem | ISubmenuItem> {
const result = (this._menuItems.get(id) || []).slice(0); let result: Array<IMenuItem | ISubmenuItem>;
if (this._menuItems.has(id)) {
result = [...this._menuItems.get(id)!];
} else {
result = [];
}
if (id === MenuId.CommandPalette) { if (id === MenuId.CommandPalette) {
// CommandPalette is special because it shows // CommandPalette is special because it shows
// all commands by default // all commands by default
@@ -232,12 +268,12 @@ export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {
private _appendImplicitItems(result: Array<IMenuItem | ISubmenuItem>) { private _appendImplicitItems(result: Array<IMenuItem | ISubmenuItem>) {
const set = new Set<string>(); const set = new Set<string>();
const temp = result.filter(item => { return isIMenuItem(item); }) as IMenuItem[]; for (const item of result) {
if (isIMenuItem(item)) {
for (const { command, alt } of temp) { set.add(item.command.id);
set.add(command.id); if (item.alt) {
if (alt) { set.add(item.alt.id);
set.add(alt.id); }
} }
} }
this._commands.forEach((command, id) => { this._commands.forEach((command, id) => {
@@ -441,14 +477,13 @@ export function registerAction2(ctor: { new(): Action2 }): IDisposable {
// menu // menu
if (Array.isArray(menu)) { if (Array.isArray(menu)) {
for (let item of menu) { disposables.add(MenuRegistry.appendMenuItems(menu.map(item => ({ id: item.id, item: { command, ...item } }))));
disposables.add(MenuRegistry.appendMenuItem(item.id, { command: { ...command }, ...item }));
}
} else if (menu) { } else if (menu) {
disposables.add(MenuRegistry.appendMenuItem(menu.id, { command: { ...command }, ...menu })); disposables.add(MenuRegistry.appendMenuItem(menu.id, { command, ...menu }));
} }
if (f1) { if (f1) {
disposables.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: command })); disposables.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command }));
} }
// keybinding // keybinding
@@ -45,7 +45,7 @@ class Menu implements IMenu {
// rebuild this menu whenever the menu registry reports an // rebuild this menu whenever the menu registry reports an
// event for this MenuId // event for this MenuId
this._dispoables.add(Event.debounce( this._dispoables.add(Event.debounce(
Event.filter(MenuRegistry.onDidChangeMenu, menuId => menuId === this._id), Event.filter(MenuRegistry.onDidChangeMenu, set => set.has(this._id)),
() => { }, () => { },
50 50
)(this._build, this)); )(this._build, this));
+1 -2
View File
@@ -9,7 +9,6 @@ import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/com
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { LinkedList } from 'vs/base/common/linkedList'; import { LinkedList } from 'vs/base/common/linkedList';
import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { keys } from 'vs/base/common/map';
import { Iterable } from 'vs/base/common/iterator'; import { Iterable } from 'vs/base/common/iterator';
export const ICommandService = createDecorator<ICommandService>('commandService'); export const ICommandService = createDecorator<ICommandService>('commandService');
@@ -130,7 +129,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
getCommands(): ICommandsMap { getCommands(): ICommandsMap {
const result = new Map<string, ICommand>(); const result = new Map<string, ICommand>();
for (const key of keys(this._commands)) { for (const key of this._commands.keys()) {
const command = this.getCommand(key); const command = this.getCommand(key);
if (command) { if (command) {
result.set(key, command); result.set(key, command);
@@ -231,7 +231,7 @@ export class ConfigurationModelParser {
} }
public parseContent(content: string | null | undefined): void { public parseContent(content: string | null | undefined): void {
if (content) { if (!types.isUndefinedOrNull(content)) {
const raw = this.doParseContent(content); const raw = this.doParseContent(content);
this.parseRaw(raw); this.parseRaw(raw);
} }
@@ -677,7 +677,7 @@ export class Configuration {
overrides: this._workspaceConfiguration.overrides, overrides: this._workspaceConfiguration.overrides,
keys: this._workspaceConfiguration.keys keys: this._workspaceConfiguration.keys
}, },
folders: this._folderConfigurations.keys().reduce<[UriComponents, IConfigurationModel][]>((result, folder) => { folders: [...this._folderConfigurations.keys()].reduce<[UriComponents, IConfigurationModel][]>((result, folder) => {
const { contents, overrides, keys } = this._folderConfigurations.get(folder)!; const { contents, overrides, keys } = this._folderConfigurations.get(folder)!;
result.push([folder, { contents, overrides, keys }]); result.push([folder, { contents, overrides, keys }]);
return result; return result;
@@ -21,14 +21,13 @@ import { isLinux, isWindows } from 'vs/base/common/platform';
import { DisposableStore } from 'vs/base/common/lifecycle'; import { DisposableStore } from 'vs/base/common/lifecycle';
import { isEqual, joinPath } from 'vs/base/common/resources'; import { isEqual, joinPath } from 'vs/base/common/resources';
import { VSBuffer, VSBufferReadable, streamToBufferReadableStream, VSBufferReadableStream, bufferToReadable, bufferToStream, streamToBuffer } from 'vs/base/common/buffer'; import { VSBuffer, VSBufferReadable, streamToBufferReadableStream, VSBufferReadableStream, bufferToReadable, bufferToStream, streamToBuffer } from 'vs/base/common/buffer';
import { find } from 'vs/base/common/arrays';
function getByName(root: IFileStat, name: string): IFileStat | undefined { function getByName(root: IFileStat, name: string): IFileStat | undefined {
if (root.children === undefined) { if (root.children === undefined) {
return undefined; return undefined;
} }
return find(root.children, child => child.name === name); return root.children.find(child => child.name === name);
} }
function toLineByLineReadable(content: string): VSBufferReadable { function toLineByLineReadable(content: string): VSBufferReadable {
@@ -442,7 +441,7 @@ suite('Disk File Service', function () {
assert.equal(resolved.isDirectory, true); assert.equal(resolved.isDirectory, true);
assert.equal(resolved.children!.length, 9); assert.equal(resolved.children!.length, 9);
const resolvedLink = resolved.children?.filter(child => child.name === 'bar' && child.isSymbolicLink)[0]; const resolvedLink = resolved.children?.find(child => child.name === 'bar' && child.isSymbolicLink);
assert.ok(resolvedLink); assert.ok(resolvedLink);
assert.ok(!resolvedLink?.isDirectory); assert.ok(!resolvedLink?.isDirectory);
+31 -39
View File
@@ -3,86 +3,78 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { isEmptyObject } from 'vs/base/common/types'; export class Node<T> {
import { forEach } from 'vs/base/common/collections';
export interface Node<T> { readonly data: T;
data: T; readonly incoming = new Map<string, Node<T>>();
incoming: { [key: string]: Node<T> }; readonly outgoing = new Map<string, Node<T>>();
outgoing: { [key: string]: Node<T> };
constructor(data: T) {
this.data = data;
} }
function newNode<T>(data: T): Node<T> {
return {
data: data,
incoming: Object.create(null),
outgoing: Object.create(null)
};
} }
export class Graph<T> { export class Graph<T> {
private _nodes: { [key: string]: Node<T> } = Object.create(null); private readonly _nodes = new Map<string, Node<T>>();
constructor(private _hashFn: (element: T) => string) { constructor(private readonly _hashFn: (element: T) => string) {
// empty // empty
} }
roots(): Node<T>[] { roots(): Node<T>[] {
const ret: Node<T>[] = []; const ret: Node<T>[] = [];
forEach(this._nodes, entry => { for (let node of this._nodes.values()) {
if (isEmptyObject(entry.value.outgoing)) { if (node.outgoing.size === 0) {
ret.push(entry.value); ret.push(node);
}
} }
});
return ret; return ret;
} }
insertEdge(from: T, to: T): void { insertEdge(from: T, to: T): void {
const fromNode = this.lookupOrInsertNode(from), const fromNode = this.lookupOrInsertNode(from);
toNode = this.lookupOrInsertNode(to); const toNode = this.lookupOrInsertNode(to);
fromNode.outgoing[this._hashFn(to)] = toNode; fromNode.outgoing.set(this._hashFn(to), toNode);
toNode.incoming[this._hashFn(from)] = fromNode; toNode.incoming.set(this._hashFn(from), fromNode);
} }
removeNode(data: T): void { removeNode(data: T): void {
const key = this._hashFn(data); const key = this._hashFn(data);
delete this._nodes[key]; this._nodes.delete(key);
forEach(this._nodes, (entry) => { for (let node of this._nodes.values()) {
delete entry.value.outgoing[key]; node.outgoing.delete(key);
delete entry.value.incoming[key]; node.incoming.delete(key);
}); }
} }
lookupOrInsertNode(data: T): Node<T> { lookupOrInsertNode(data: T): Node<T> {
const key = this._hashFn(data); const key = this._hashFn(data);
let node = this._nodes[key]; let node = this._nodes.get(key);
if (!node) { if (!node) {
node = new Node(data); node = new Node(data);
this._nodes[key] = node; this._nodes.set(key, node);
} }
return node; return node;
} }
lookup(data: T): Node<T> { lookup(data: T): Node<T> | undefined {
return this._nodes[this._hashFn(data)]; return this._nodes.get(this._hashFn(data));
} }
isEmpty(): boolean { isEmpty(): boolean {
for (const _key in this._nodes) { return this._nodes.size === 0;
return false;
}
return true;
} }
toString(): string { toString(): string {
let data: string[] = []; let data: string[] = [];
forEach(this._nodes, entry => { for (let [key, value] of this._nodes) {
data.push(`${entry.key}, (incoming)[${Object.keys(entry.value.incoming).join(', ')}], (outgoing)[${Object.keys(entry.value.outgoing).join(',')}]`); data.push(`${key}, (incoming)[${[...value.incoming.keys()].join(', ')}], (outgoing)[${[...value.outgoing.keys()].join(',')}]`);
});
}
return data.join('\n'); return data.join('\n');
} }
} }
@@ -19,7 +19,7 @@ suite('Graph', () => {
test('inserts nodes when not there yet', function () { test('inserts nodes when not there yet', function () {
assert.deepEqual(graph.lookup('ddd'), null); assert.deepEqual(graph.lookup('ddd'), null);
assert.deepEqual(graph.lookupOrInsertNode('ddd').data, 'ddd'); assert.deepEqual(graph.lookupOrInsertNode('ddd').data, 'ddd');
assert.deepEqual(graph.lookup('ddd').data, 'ddd'); assert.deepEqual(graph.lookup('ddd')!.data, 'ddd');
}); });
test('can remove nodes and get length', function () { test('can remove nodes and get length', function () {
+4 -3
View File
@@ -658,6 +658,7 @@ abstract class ResourceNavigator<T> extends Disposable {
onDidChangeFocus: Event<{ browserEvent?: UIEvent }>, onDidChangeFocus: Event<{ browserEvent?: UIEvent }>,
onDidChangeSelection: Event<{ browserEvent?: UIEvent }>, onDidChangeSelection: Event<{ browserEvent?: UIEvent }>,
onDidOpen: Event<{ browserEvent?: UIEvent }>, onDidOpen: Event<{ browserEvent?: UIEvent }>,
readonly openOnSingleClick?: boolean
}, },
options?: IResourceNavigatorOptions options?: IResourceNavigatorOptions
) { ) {
@@ -711,7 +712,7 @@ abstract class ResourceNavigator<T> extends Disposable {
!!(<SelectionKeyboardEvent>browserEvent).preserveFocus : !!(<SelectionKeyboardEvent>browserEvent).preserveFocus :
!isDoubleClick; !isDoubleClick;
if (this.options.openOnSingleClick || isDoubleClick || isKeyboardEvent) { if (this.treeOrList.openOnSingleClick || isDoubleClick || isKeyboardEvent) {
const sideBySide = browserEvent instanceof MouseEvent && (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey); const sideBySide = browserEvent instanceof MouseEvent && (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey);
this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide, browserEvent); this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide, browserEvent);
} }
@@ -738,8 +739,8 @@ export class ListResourceNavigator<T> extends ResourceNavigator<number> {
} }
export class TreeResourceNavigator<T, TFilterData> extends ResourceNavigator<T> { export class TreeResourceNavigator<T, TFilterData> extends ResourceNavigator<T> {
constructor(tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchCompressibleObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData> | WorkbenchCompressibleAsyncDataTree<any, T, TFilterData>, options?: IResourceNavigatorOptions) { constructor(tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchCompressibleObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData> | WorkbenchCompressibleAsyncDataTree<any, T, TFilterData>, options: IResourceNavigatorOptions = {}) {
super(tree, { openOnSingleClick: tree.openOnSingleClick, ...(options || {}) }); super(tree, options);
} }
} }
+77 -84
View File
@@ -6,40 +6,64 @@
import { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays'; import { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays';
import { Schemas } from 'vs/base/common/network'; import { Schemas } from 'vs/base/common/network';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import { isEmptyObject } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { IMarkerService, IMarkerData, IResourceMarker, IMarker, MarkerStatistics, MarkerSeverity } from './markers'; import { IMarkerService, IMarkerData, IResourceMarker, IMarker, MarkerStatistics, MarkerSeverity } from './markers';
import { ResourceMap } from 'vs/base/common/map';
import { Iterable } from 'vs/base/common/iterator';
interface MapMap<V> { class DoubleResourceMap<V>{
[key: string]: { [key: string]: V };
private _byResource = new ResourceMap<Map<string, V>>();
private _byOwner = new Map<string, ResourceMap<V>>();
set(resource: URI, owner: string, value: V) {
let ownerMap = this._byResource.get(resource);
if (!ownerMap) {
ownerMap = new Map();
this._byResource.set(resource, ownerMap);
}
ownerMap.set(owner, value);
let resourceMap = this._byOwner.get(owner);
if (!resourceMap) {
resourceMap = new ResourceMap();
this._byOwner.set(owner, resourceMap);
}
resourceMap.set(resource, value);
} }
namespace MapMap { get(resource: URI, owner: string): V | undefined {
let ownerMap = this._byResource.get(resource);
export function get<V>(map: MapMap<V>, key1: string, key2: string): V | undefined { return ownerMap?.get(owner);
if (map[key1]) {
return map[key1][key2];
}
return undefined;
} }
export function set<V>(map: MapMap<V>, key1: string, key2: string, value: V): void { delete(resource: URI, owner: string): boolean {
if (!map[key1]) { let removedA = false;
map[key1] = Object.create(null); let removedB = false;
let ownerMap = this._byResource.get(resource);
if (ownerMap) {
removedA = ownerMap.delete(owner);
} }
map[key1][key2] = value; let resourceMap = this._byOwner.get(owner);
if (resourceMap) {
removedB = resourceMap.delete(resource);
}
if (removedA !== removedB) {
throw new Error('illegal state');
}
return removedA && removedB;
} }
export function remove(map: MapMap<any>, key1: string, key2: string): boolean { values(key?: URI | string): Iterable<V> {
if (map[key1] && map[key1][key2]) { if (typeof key === 'string') {
delete map[key1][key2]; return this._byOwner.get(key)?.values() ?? Iterable.empty();
if (isEmptyObject(map[key1])) {
delete map[key1];
} }
return true; if (URI.isUri(key)) {
return this._byResource.get(key)?.values() ?? Iterable.empty();
} }
return false;
return Iterable.map(Iterable.concat(...this._byOwner.values()), map => map[1]);
} }
} }
@@ -50,9 +74,9 @@ class MarkerStats implements MarkerStatistics {
warnings: number = 0; warnings: number = 0;
unknowns: number = 0; unknowns: number = 0;
private _data?: { [resource: string]: MarkerStatistics } = Object.create(null); private readonly _data = new ResourceMap<MarkerStatistics>();
private _service: IMarkerService; private readonly _service: IMarkerService;
private _subscription: IDisposable; private readonly _subscription: IDisposable;
constructor(service: IMarkerService) { constructor(service: IMarkerService) {
this._service = service; this._service = service;
@@ -61,23 +85,17 @@ class MarkerStats implements MarkerStatistics {
dispose(): void { dispose(): void {
this._subscription.dispose(); this._subscription.dispose();
this._data = undefined;
} }
private _update(resources: readonly URI[]): void { private _update(resources: readonly URI[]): void {
if (!this._data) {
return;
}
for (const resource of resources) { for (const resource of resources) {
const key = resource.toString(); const oldStats = this._data.get(resource);
const oldStats = this._data[key];
if (oldStats) { if (oldStats) {
this._substract(oldStats); this._substract(oldStats);
} }
const newStats = this._resourceStats(resource); const newStats = this._resourceStats(resource);
this._add(newStats); this._add(newStats);
this._data[key] = newStats; this._data.set(resource, newStats);
} }
} }
@@ -124,10 +142,10 @@ export class MarkerService implements IMarkerService {
_serviceBrand: undefined; _serviceBrand: undefined;
private readonly _onMarkerChanged = new Emitter<readonly URI[]>(); private readonly _onMarkerChanged = new Emitter<readonly URI[]>();
private _onMarkerChangedEvent: Event<readonly URI[]> = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0); readonly onMarkerChanged: Event<readonly URI[]> = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0);
private _byResource: MapMap<IMarker[]> = Object.create(null);
private _byOwner: MapMap<IMarker[]> = Object.create(null); private readonly _data = new DoubleResourceMap<IMarker[]>();
private _stats: MarkerStats; private readonly _stats: MarkerStats;
constructor() { constructor() {
this._stats = new MarkerStats(this); this._stats = new MarkerStats(this);
@@ -137,10 +155,6 @@ export class MarkerService implements IMarkerService {
this._stats.dispose(); this._stats.dispose();
} }
get onMarkerChanged(): Event<readonly URI[]> {
return this._onMarkerChangedEvent;
}
getStatistics(): MarkerStatistics { getStatistics(): MarkerStatistics {
return this._stats; return this._stats;
} }
@@ -155,12 +169,8 @@ export class MarkerService implements IMarkerService {
if (isFalsyOrEmpty(markerData)) { if (isFalsyOrEmpty(markerData)) {
// remove marker for this (owner,resource)-tuple // remove marker for this (owner,resource)-tuple
const a = MapMap.remove(this._byResource, resource.toString(), owner); const removed = this._data.delete(resource, owner);
const b = MapMap.remove(this._byOwner, owner, resource.toString()); if (removed) {
if (a !== b) {
throw new Error('invalid marker service state');
}
if (a && b) {
this._onMarkerChanged.fire([resource]); this._onMarkerChanged.fire([resource]);
} }
@@ -173,8 +183,7 @@ export class MarkerService implements IMarkerService {
markers.push(marker); markers.push(marker);
} }
} }
MapMap.set(this._byResource, resource.toString(), owner, markers); this._data.set(resource, owner, markers);
MapMap.set(this._byOwner, owner, resource.toString(), markers);
this._onMarkerChanged.fire([resource]); this._onMarkerChanged.fire([resource]);
} }
} }
@@ -216,21 +225,15 @@ export class MarkerService implements IMarkerService {
changeAll(owner: string, data: IResourceMarker[]): void { changeAll(owner: string, data: IResourceMarker[]): void {
const changes: URI[] = []; const changes: URI[] = [];
const map = this._byOwner[owner];
// remove old marker // remove old marker
if (map) { const existing = this._data.values(owner);
delete this._byOwner[owner]; if (existing) {
for (const resource in map) { for (let data of existing) {
const entry = MapMap.get(this._byResource, resource, owner); const first = Iterable.first(data);
if (entry) {
// remeber what we remove
const [first] = entry;
if (first) { if (first) {
changes.push(first.resource); changes.push(first.resource);
} this._data.delete(first.resource, owner);
// actual remove
MapMap.remove(this._byResource, resource, owner);
} }
} }
} }
@@ -239,16 +242,16 @@ export class MarkerService implements IMarkerService {
if (isNonEmptyArray(data)) { if (isNonEmptyArray(data)) {
// group by resource // group by resource
const groups: { [resource: string]: IMarker[] } = Object.create(null); const groups = new ResourceMap<IMarker[]>();
for (const { resource, marker: markerData } of data) { for (const { resource, marker: markerData } of data) {
const marker = MarkerService._toMarker(owner, resource, markerData); const marker = MarkerService._toMarker(owner, resource, markerData);
if (!marker) { if (!marker) {
// filter bad markers // filter bad markers
continue; continue;
} }
const array = groups[resource.toString()]; const array = groups.get(resource);
if (!array) { if (!array) {
groups[resource.toString()] = [marker]; groups.set(resource, [marker]);
changes.push(resource); changes.push(resource);
} else { } else {
array.push(marker); array.push(marker);
@@ -256,9 +259,8 @@ export class MarkerService implements IMarkerService {
} }
// insert all // insert all
for (const resource in groups) { for (const [resource, value] of groups) {
MapMap.set(this._byResource, resource, owner, groups[resource]); this._data.set(resource, owner, value);
MapMap.set(this._byOwner, owner, resource, groups[resource]);
} }
} }
@@ -277,7 +279,7 @@ export class MarkerService implements IMarkerService {
if (owner && resource) { if (owner && resource) {
// exactly one owner AND resource // exactly one owner AND resource
const data = MapMap.get(this._byResource, resource.toString(), owner); const data = this._data.get(resource, owner);
if (!data) { if (!data) {
return []; return [];
} else { } else {
@@ -296,9 +298,8 @@ export class MarkerService implements IMarkerService {
} else if (!owner && !resource) { } else if (!owner && !resource) {
// all // all
const result: IMarker[] = []; const result: IMarker[] = [];
for (const key1 in this._byResource) { for (let markers of this._data.values()) {
for (const key2 in this._byResource[key1]) { for (let data of markers) {
for (const data of this._byResource[key1][key2]) {
if (MarkerService._accept(data, severities)) { if (MarkerService._accept(data, severities)) {
const newLen = result.push(data); const newLen = result.push(data);
if (take > 0 && newLen === take) { if (take > 0 && newLen === take) {
@@ -307,22 +308,14 @@ export class MarkerService implements IMarkerService {
} }
} }
} }
}
return result; return result;
} else { } else {
// of one resource OR owner // of one resource OR owner
const map: { [key: string]: IMarker[] } | undefined = owner const iterable = this._data.values(resource ?? owner!);
? this._byOwner[owner]
: resource ? this._byResource[resource.toString()] : undefined;
if (!map) {
return [];
}
const result: IMarker[] = []; const result: IMarker[] = [];
for (const key in map) { for (const markers of iterable) {
for (const data of map[key]) { for (const data of markers) {
if (MarkerService._accept(data, severities)) { if (MarkerService._accept(data, severities)) {
const newLen = result.push(data); const newLen = result.push(data);
if (take > 0 && newLen === take) { if (take > 0 && newLen === take) {
@@ -341,16 +334,16 @@ export class MarkerService implements IMarkerService {
// --- event debounce logic // --- event debounce logic
private static _dedupeMap: { [uri: string]: boolean }; private static _dedupeMap: ResourceMap<true>;
private static _debouncer(last: URI[] | undefined, event: readonly URI[]): URI[] { private static _debouncer(last: URI[] | undefined, event: readonly URI[]): URI[] {
if (!last) { if (!last) {
MarkerService._dedupeMap = Object.create(null); MarkerService._dedupeMap = new ResourceMap();
last = []; last = [];
} }
for (const uri of event) { for (const uri of event) {
if (MarkerService._dedupeMap[uri.toString()] === undefined) { if (!MarkerService._dedupeMap.has(uri)) {
MarkerService._dedupeMap[uri.toString()] = true; MarkerService._dedupeMap.set(uri, true);
last.push(uri); last.push(uri);
} }
} }
@@ -703,7 +703,8 @@ export class Menubar {
} }
// DevTools focused // DevTools focused
if (activeWindow.webContents.isDevToolsFocused()) { if (activeWindow.webContents.isDevToolsFocused() &&
activeWindow.webContents.devToolsWebContents) {
return contextSpecificHandlers.inDevTools(activeWindow.webContents.devToolsWebContents); return contextSpecificHandlers.inDevTools(activeWindow.webContents.devToolsWebContents);
} }
+35 -8
View File
@@ -56,6 +56,11 @@ export interface IIconRegistry {
*/ */
getIcons(): IconContribution[]; getIcons(): IconContribution[];
/**
* Get the icon for the given id
*/
getIcon(id: string): IconContribution | undefined;
/** /**
* JSON schema for an object to assign icon values to one of the color contributions. * JSON schema for an object to assign icon values to one of the color contributions.
*/ */
@@ -130,6 +135,10 @@ class IconRegistry implements IIconRegistry {
return Object.keys(this.iconsById).map(id => this.iconsById[id]); return Object.keys(this.iconsById).map(id => this.iconsById[id]);
} }
public getIcon(id: string): IconContribution | undefined {
return this.iconsById[id];
}
public getIconSchema(): IJSONSchema { public getIconSchema(): IJSONSchema {
return this.iconSchema; return this.iconSchema;
} }
@@ -139,16 +148,34 @@ class IconRegistry implements IIconRegistry {
} }
public toString() { public toString() {
let sorter = (a: string, b: string) => { const sorter = (i1: IconContribution, i2: IconContribution) => {
let cat1 = a.indexOf('.') === -1 ? 0 : 1; const isThemeIcon1 = ThemeIcon.isThemeIcon(i1.defaults);
let cat2 = b.indexOf('.') === -1 ? 0 : 1; const isThemeIcon2 = ThemeIcon.isThemeIcon(i2.defaults);
if (cat1 !== cat2) { if (isThemeIcon1 !== isThemeIcon2) {
return cat1 - cat2; return isThemeIcon1 ? -1 : 1;
} }
return a.localeCompare(b); return i1.id.localeCompare(i2.id);
};
const classNames = (i: IconContribution) => {
while (ThemeIcon.isThemeIcon(i.defaults)) {
i = this.iconsById[i.defaults.id];
}
return `codicon codicon-${i ? i.id : ''}`;
}; };
return Object.keys(this.iconsById).sort(sorter).map(k => `- \`${k}\`: ${this.iconsById[k].description}`).join('\n'); let reference = [];
let docCss = [];
const contributions = Object.keys(this.iconsById).map(key => this.iconsById[key]);
for (const i of contributions.sort(sorter)) {
reference.push(`|<i class="${classNames(i)}"></i>|${i.id}|${ThemeIcon.isThemeIcon(i.defaults) ? i.defaults.id : ''}|`);
if (!ThemeIcon.isThemeIcon((i.defaults))) {
docCss.push(`.codicon-${i.id}:before { content: "${i.defaults.character}" }`);
}
}
return reference.join('\n') + '\n\n' + docCss.join('\n');
} }
} }
@@ -186,4 +213,4 @@ iconRegistry.onDidChangeSchema(() => {
}); });
// setTimeout(_ => console.log(colorRegistry.toString()), 5000); //setTimeout(_ => console.log(iconRegistry.toString()), 5000);
@@ -167,10 +167,16 @@ export abstract class AbstractSynchroniser extends Disposable {
if (e instanceof UserDataSyncError) { if (e instanceof UserDataSyncError) {
switch (e.code) { switch (e.code) {
case UserDataSyncErrorCode.RemotePreconditionFailed: case UserDataSyncErrorCode.RemotePreconditionFailed:
// Rejected as there is a new remote version. Syncing again, // Rejected as there is a new remote version. Syncing again...
this.logService.info(`${this.syncResourceLogLabel}: Failed to synchronize as there is a new remote version available. Synchronizing again...`); this.logService.info(`${this.syncResourceLogLabel}: Failed to synchronize as there is a new remote version available. Synchronizing again...`);
// Avoid cache and get latest remote user data - https://github.com/microsoft/vscode/issues/90624 // Avoid cache and get latest remote user data - https://github.com/microsoft/vscode/issues/90624
remoteUserData = await this.getRemoteUserData(null); remoteUserData = await this.getRemoteUserData(null);
// Get the latest last sync user data. Because multiples parallel syncs (in Web) could share same last sync data
// and one of them successfully updated remote and last sync state.
lastSyncUserData = await this.getLastSyncUserData();
return this.doSync(remoteUserData, lastSyncUserData); return this.doSync(remoteUserData, lastSyncUserData);
} }
} }
@@ -318,7 +318,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
if (!currentWindowsState.lastActiveWindow) { if (!currentWindowsState.lastActiveWindow) {
let activeWindow = this.getLastActiveWindow(); let activeWindow = this.getLastActiveWindow();
if (!activeWindow || activeWindow.isExtensionDevelopmentHost) { if (!activeWindow || activeWindow.isExtensionDevelopmentHost) {
activeWindow = WindowsMainService.WINDOWS.filter(window => !window.isExtensionDevelopmentHost)[0]; activeWindow = WindowsMainService.WINDOWS.find(window => !window.isExtensionDevelopmentHost);
} }
if (activeWindow) { if (activeWindow) {
@@ -327,7 +327,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
} }
// 2.) Find extension host window // 2.) Find extension host window
const extensionHostWindow = WindowsMainService.WINDOWS.filter(window => window.isExtensionDevelopmentHost && !window.isExtensionTestHost)[0]; const extensionHostWindow = WindowsMainService.WINDOWS.find(window => window.isExtensionDevelopmentHost && !window.isExtensionTestHost);
if (extensionHostWindow) { if (extensionHostWindow) {
currentWindowsState.lastPluginDevelopmentHostWindow = this.toWindowState(extensionHostWindow); currentWindowsState.lastPluginDevelopmentHostWindow = this.toWindowState(extensionHostWindow);
} }
+1 -1
View File
@@ -168,7 +168,7 @@ function findWindowOnFilePath<W extends IWindowContext>(windows: W[], fileUri: U
export function getLastActiveWindow<W extends IWindowContext>(windows: W[]): W | undefined { export function getLastActiveWindow<W extends IWindowContext>(windows: W[]): W | undefined {
const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime));
return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0]; return windows.find(window => window.lastFocusTime === lastFocusedDate);
} }
export function findWindowOnWorkspace<W extends IWindowContext>(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null { export function findWindowOnWorkspace<W extends IWindowContext>(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null {
+45 -2
View File
@@ -7897,7 +7897,7 @@ declare module 'vscode' {
* This will trigger the view to update the changed element/root and its children recursively (if shown). * This will trigger the view to update the changed element/root and its children recursively (if shown).
* To signal that root has changed, do not pass any argument or pass `undefined` or `null`. * To signal that root has changed, do not pass any argument or pass `undefined` or `null`.
*/ */
onDidChangeTreeData?: Event<T | undefined | null>; onDidChangeTreeData?: Event<T | undefined | null | void>;
/** /**
* Get [TreeItem](#TreeItem) representation of the `element` * Get [TreeItem](#TreeItem) representation of the `element`
@@ -10486,6 +10486,23 @@ declare module 'vscode' {
// Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source). // Properties: see details [here](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Source).
} }
/**
* A DebugConfigurationProviderTriggerKind specifies when the `provideDebugConfigurations` method of a `DebugConfigurationProvider` is triggered.
* Currently there are two situations: to provide the initial debug configurations for a newly created launch.json or
* to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command).
* A trigger kind is used when registering a `DebugConfigurationProvider` with #debug.registerDebugConfigurationProvider.
*/
export enum DebugConfigurationProviderTriggerKind {
/**
* `DebugConfigurationProvider.provideDebugConfigurations` is called to provide the initial debug configurations for a newly created launch.json.
*/
Initial = 1,
/**
* `DebugConfigurationProvider.provideDebugConfigurations` is called to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command).
*/
Dynamic = 2
}
/** /**
* Namespace for debug functionality. * Namespace for debug functionality.
*/ */
@@ -10539,13 +10556,19 @@ declare module 'vscode' {
/** /**
* Register a [debug configuration provider](#DebugConfigurationProvider) for a specific debug type. * Register a [debug configuration provider](#DebugConfigurationProvider) for a specific debug type.
* The optional [triggerKind](#DebugConfigurationProviderTriggerKind) can be used to specify when the `provideDebugConfigurations` method of the provider is triggered.
* Currently two trigger kinds are possible: with the value `Initial` (or if no trigger kind argument is given) the `provideDebugConfigurations` method is used to provide the initial debug configurations to be copied into a newly created launch.json.
* With the trigger kind `Dynamic` the `provideDebugConfigurations` method is used to dynamically determine debug configurations to be presented to the user (in addition to the static configurations from the launch.json).
* Please note that the `triggerKind` argument only applies to the `provideDebugConfigurations` method: so the `resolveDebugConfiguration` methods are not affected at all.
* Registering a single provider with resolve methods for different trigger kinds, results in the same resolve methods called multiple times.
* More than one provider can be registered for the same type. * More than one provider can be registered for the same type.
* *
* @param type The debug type for which the provider is registered. * @param type The debug type for which the provider is registered.
* @param provider The [debug configuration provider](#DebugConfigurationProvider) to register. * @param provider The [debug configuration provider](#DebugConfigurationProvider) to register.
* @param triggerKind The [trigger](#DebugConfigurationProviderTrigger) for which the 'provideDebugConfiguration' method of the provider is registered. If `triggerKind` is missing, the value `DebugConfigurationProviderTriggerKind.Initial` is assumed.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed. * @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/ */
export function registerDebugConfigurationProvider(debugType: string, provider: DebugConfigurationProvider): Disposable; export function registerDebugConfigurationProvider(debugType: string, provider: DebugConfigurationProvider, triggerKind?: DebugConfigurationProviderTriggerKind): Disposable;
/** /**
* Register a [debug adapter descriptor factory](#DebugAdapterDescriptorFactory) for a specific debug type. * Register a [debug adapter descriptor factory](#DebugAdapterDescriptorFactory) for a specific debug type.
@@ -10875,6 +10898,21 @@ declare module 'vscode' {
provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult<Range[]>; provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult<Range[]>;
} }
/**
* Represents a [comment controller](#CommentController)'s [options](#CommentController.options).
*/
export interface CommentOptions {
/**
* An optional string to show on the comment input box when it's collapsed.
*/
prompt?: string;
/**
* An optional string to show as placeholder in the comment input box when it's focused.
*/
placeHolder?: string;
}
/** /**
* A comment controller is able to provide [comments](#CommentThread) support to the editor and * A comment controller is able to provide [comments](#CommentThread) support to the editor and
* provide users various ways to interact with comments. * provide users various ways to interact with comments.
@@ -10890,6 +10928,11 @@ declare module 'vscode' {
*/ */
readonly label: string; readonly label: string;
/**
* Comment controller options
*/
options?: CommentOptions;
/** /**
* Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri.
* *
+66 -80
View File
@@ -25,7 +25,7 @@ declare module 'vscode' {
displayName: string; displayName: string;
id: string; id: string;
}; };
scopes: string[] scopes: string[];
} }
/** /**
@@ -141,12 +141,12 @@ declare module 'vscode' {
* within a session has changed for a provider. Fires with the ids of the providers * within a session has changed for a provider. Fires with the ids of the providers
* that have had session data change. * that have had session data change.
*/ */
export const onDidChangeSessions: Event<{ [providerId: string]: AuthenticationSessionsChangeEvent }>; export const onDidChangeSessions: Event<{ [providerId: string]: AuthenticationSessionsChangeEvent; }>;
} }
//#endregion //#endregion
//#region Alex - resolvers //#region @alexdima - resolvers
export interface RemoteAuthorityResolverContext { export interface RemoteAuthorityResolverContext {
resolveAttempt: number; resolveAttempt: number;
@@ -160,20 +160,20 @@ declare module 'vscode' {
} }
export interface ResolvedOptions { export interface ResolvedOptions {
extensionHostEnv?: { [key: string]: string | null }; extensionHostEnv?: { [key: string]: string | null; };
} }
export interface TunnelOptions { export interface TunnelOptions {
remoteAddress: { port: number, host: string }; remoteAddress: { port: number, host: string; };
// The desired local port. If this port can't be used, then another will be chosen. // The desired local port. If this port can't be used, then another will be chosen.
localAddressPort?: number; localAddressPort?: number;
label?: string; label?: string;
} }
export interface TunnelDescription { export interface TunnelDescription {
remoteAddress: { port: number, host: string }; remoteAddress: { port: number, host: string; };
//The complete local address(ex. localhost:1234) //The complete local address(ex. localhost:1234)
localAddress: { port: number, host: string } | string; localAddress: { port: number, host: string; } | string;
} }
export interface Tunnel extends TunnelDescription { export interface Tunnel extends TunnelDescription {
@@ -248,7 +248,7 @@ declare module 'vscode' {
export interface ResourceLabelFormatting { export interface ResourceLabelFormatting {
label: string; // myLabel:/${path} label: string; // myLabel:/${path}
// TODO@isi // TODO@isidorn
// eslint-disable-next-line vscode-dts-literal-or-types // eslint-disable-next-line vscode-dts-literal-or-types
separator: '/' | '\\' | ''; separator: '/' | '\\' | '';
tildify?: boolean; tildify?: boolean;
@@ -284,7 +284,7 @@ declare module 'vscode' {
//#region read/write in chunks: https://github.com/microsoft/vscode/issues/84515 //#region read/write in chunks: https://github.com/microsoft/vscode/issues/84515
export interface FileSystemProvider { export interface FileSystemProvider {
open?(resource: Uri, options: { create: boolean }): number | Thenable<number>; open?(resource: Uri, options: { create: boolean; }): number | Thenable<number>;
close?(fd: number): void | Thenable<void>; close?(fd: number): void | Thenable<void>;
read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable<number>; read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable<number>;
write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable<number>; write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable<number>;
@@ -326,7 +326,7 @@ declare module 'vscode' {
/** /**
* A file glob pattern to match file paths against. * A file glob pattern to match file paths against.
* TODO@roblou - merge this with the GlobPattern docs/definition in vscode.d.ts. * TODO@roblourens merge this with the GlobPattern docs/definition in vscode.d.ts.
* @see [GlobPattern](#GlobPattern) * @see [GlobPattern](#GlobPattern)
*/ */
export type GlobString = string; export type GlobString = string;
@@ -731,42 +731,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region debug: https://github.com/microsoft/vscode/issues/88230 //#region debug
/**
* A DebugConfigurationProviderTriggerKind specifies when the `provideDebugConfigurations` method of a `DebugConfigurationProvider` is triggered.
* Currently there are two situations: to provide the initial debug configurations for a newly created launch.json or
* to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command).
* A trigger kind is used when registering a `DebugConfigurationProvider` with #debug.registerDebugConfigurationProvider.
*/
export enum DebugConfigurationProviderTriggerKind {
/**
* `DebugConfigurationProvider.provideDebugConfigurations` is called to provide the initial debug configurations for a newly created launch.json.
*/
Initial = 1,
/**
* `DebugConfigurationProvider.provideDebugConfigurations` is called to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command).
*/
Dynamic = 2
}
export namespace debug {
/**
* Register a [debug configuration provider](#DebugConfigurationProvider) for a specific debug type.
* The optional [triggerKind](#DebugConfigurationProviderTriggerKind) can be used to specify when the `provideDebugConfigurations` method of the provider is triggered.
* Currently two trigger kinds are possible: with the value `Initial` (or if no trigger kind argument is given) the `provideDebugConfigurations` method is used to provide the initial debug configurations to be copied into a newly created launch.json.
* With the trigger kind `Dynamic` the `provideDebugConfigurations` method is used to dynamically determine debug configurations to be presented to the user (in addition to the static configurations from the launch.json).
* Please note that the `triggerKind` argument only applies to the `provideDebugConfigurations` method: so the `resolveDebugConfiguration` methods are not affected at all.
* Registering a single provider with resolve methods for different trigger kinds, results in the same resolve methods called multiple times.
* More than one provider can be registered for the same type.
*
* @param type The debug type for which the provider is registered.
* @param provider The [debug configuration provider](#DebugConfigurationProvider) to register.
* @param triggerKind The [trigger](#DebugConfigurationProviderTrigger) for which the 'provideDebugConfiguration' method of the provider is registered.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerDebugConfigurationProvider(debugType: string, provider: DebugConfigurationProvider, triggerKind?: DebugConfigurationProviderTriggerKind): Disposable;
}
// deprecated debug API // deprecated debug API
@@ -809,7 +774,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Joao: SCM validation //#region @joaomoreno: SCM validation
/** /**
* Represents the validation type of the Source Control input. * Represents the validation type of the Source Control input.
@@ -859,7 +824,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Joao: SCM selected provider //#region @joaomoreno: SCM selected provider
export interface SourceControl { export interface SourceControl {
@@ -1062,7 +1027,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Joh -> exclusive document filters //#region @jrieken -> exclusive document filters
export interface DocumentFilter { export interface DocumentFilter {
exclusive?: boolean; exclusive?: boolean;
@@ -1070,7 +1035,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Alex - OnEnter enhancement //#region @alexdima - OnEnter enhancement
export interface OnEnterRule { export interface OnEnterRule {
/** /**
* This rule will only execute if the text above the this line matches this regular expression. * This rule will only execute if the text above the this line matches this regular expression.
@@ -1579,7 +1544,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Peng: Notebook //#region @rebornix: Notebook
export enum CellKind { export enum CellKind {
Markdown = 1, Markdown = 1,
@@ -1632,7 +1597,7 @@ declare module 'vscode' {
* } * }
* } * }
*/ */
data: { [key: string]: any }; data: { [key: string]: any; };
} }
export type CellOutput = CellStreamOutput | CellErrorOutput | CellDisplayOutput; export type CellOutput = CellStreamOutput | CellErrorOutput | CellDisplayOutput;
@@ -1713,6 +1678,8 @@ declare module 'vscode' {
* Defaults to true. * Defaults to true.
*/ */
hasExecutionOrder?: boolean; hasExecutionOrder?: boolean;
displayOrder?: GlobPattern[];
} }
export interface NotebookDocument { export interface NotebookDocument {
@@ -1804,13 +1771,54 @@ declare module 'vscode' {
// readonly contentChanges: ReadonlyArray<TextDocumentContentChangeEvent>; // readonly contentChanges: ReadonlyArray<TextDocumentContentChangeEvent>;
} }
export interface NotebookCellData {
readonly cellKind: CellKind;
readonly source: string;
language: string;
outputs: CellOutput[];
metadata: NotebookCellMetadata;
}
export interface NotebookData {
readonly cells: NotebookCellData[];
readonly languages: string[];
readonly metadata: NotebookDocumentMetadata;
}
export interface NotebookContentProvider {
openNotebook(uri: Uri): NotebookData | Promise<NotebookData>;
saveNotebook(document: NotebookDocument, cancellation: CancellationToken): Promise<void>;
saveNotebookAs(targetResource: Uri, document: NotebookDocument, cancellation: CancellationToken): Promise<void>;
readonly onDidChangeNotebook: Event<void>;
// revert?(document: NotebookDocument, cancellation: CancellationToken): Thenable<void>;
// backup?(document: NotebookDocument, cancellation: CancellationToken): Thenable<CustomDocumentBackup>;
/**
* Responsible for filling in outputs for the cell
*/
executeCell(document: NotebookDocument, cell: NotebookCell | undefined, token: CancellationToken): Promise<void>;
}
export namespace notebook { export namespace notebook {
export function registerNotebookContentProvider(
notebookType: string,
provider: NotebookContentProvider
): Disposable;
export function registerNotebookProvider( export function registerNotebookProvider(
notebookType: string, notebookType: string,
provider: NotebookProvider provider: NotebookProvider
): Disposable; ): Disposable;
export function registerNotebookOutputRenderer(type: string, outputSelector: NotebookOutputSelector, renderer: NotebookOutputRenderer): Disposable; export function registerNotebookOutputRenderer(
type: string,
outputSelector: NotebookOutputSelector,
renderer: NotebookOutputRenderer
): Disposable;
export const onDidOpenNotebookDocument: Event<NotebookDocument>;
export const onDidCloseNotebookDocument: Event<NotebookDocument>;
// export const onDidChangeVisibleNotebookEditors: Event<NotebookEditor[]>;
// remove activeNotebookDocument, now that there is activeNotebookEditor.document // remove activeNotebookDocument, now that there is activeNotebookEditor.document
export let activeNotebookDocument: NotebookDocument | undefined; export let activeNotebookDocument: NotebookDocument | undefined;
@@ -1865,7 +1873,7 @@ declare module 'vscode' {
//#endregion //#endregion
//#region eamodio - timeline: https://github.com/microsoft/vscode/issues/84297 //#region @eamodio - timeline: https://github.com/microsoft/vscode/issues/84297
export class TimelineItem { export class TimelineItem {
/** /**
@@ -1888,7 +1896,7 @@ declare module 'vscode' {
/** /**
* The icon path or [ThemeIcon](#ThemeIcon) for the timeline item. * The icon path or [ThemeIcon](#ThemeIcon) for the timeline item.
*/ */
iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; iconPath?: Uri | { light: Uri; dark: Uri; } | ThemeIcon;
/** /**
* A human readable string describing less prominent details of the timeline item. * A human readable string describing less prominent details of the timeline item.
@@ -1951,7 +1959,7 @@ declare module 'vscode' {
* Use `undefined` to signal that there are no more items to be returned. * Use `undefined` to signal that there are no more items to be returned.
*/ */
readonly cursor: string | undefined; readonly cursor: string | undefined;
} };
/** /**
* An array of [timeline items](#TimelineItem). * An array of [timeline items](#TimelineItem).
@@ -1969,7 +1977,7 @@ declare module 'vscode' {
* An optional maximum number timeline items or the all timeline items newer (inclusive) than the timestamp or id that should be returned. * An optional maximum number timeline items or the all timeline items newer (inclusive) than the timestamp or id that should be returned.
* If `undefined` all timeline items should be returned. * If `undefined` all timeline items should be returned.
*/ */
limit?: number | { timestamp: number; id?: string }; limit?: number | { timestamp: number; id?: string; };
} }
export interface TimelineProvider { export interface TimelineProvider {
@@ -2033,7 +2041,7 @@ declare module 'vscode' {
* *
* - Any code actions of `kind` are returned by the provider. * - Any code actions of `kind` are returned by the provider.
*/ */
readonly documentation?: ReadonlyArray<{ readonly kind: CodeActionKind, readonly command: Command }>; readonly documentation?: ReadonlyArray<{ readonly kind: CodeActionKind, readonly command: Command; }>;
} }
//#endregion //#endregion
@@ -2072,26 +2080,4 @@ declare module 'vscode' {
} }
//#endregion //#endregion
//#region Comment
export interface CommentOptions {
/**
* An optional string to show on the comment input box when it's collapsed.
*/
prompt?: string;
/**
* An optional string to show as placeholder in the comment input box when it's focused.
*/
placeHolder?: string;
}
export interface CommentController {
/**
* Comment controller options
*/
options?: CommentOptions;
}
//#endregion
} }
@@ -324,7 +324,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
} }
const remoteConnection = this.remoteAgentService.getConnection(); const remoteConnection = this.remoteAgentService.getConnection();
if (remoteConnection && remoteConnection.remoteAuthority === 'vsonline' && VSO_ALLOWED_EXTENSIONS.includes(extensionId)) { if (remoteConnection && remoteConnection.remoteAuthority && remoteConnection.remoteAuthority.startsWith('vsonline') && VSO_ALLOWED_EXTENSIONS.includes(extensionId)) {
return true; return true;
} }
@@ -448,8 +448,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
} }
}; };
if (supportsResolveDetails) { if (supportsResolveDetails) {
provider.resolveCompletionItem = (model, position, suggestion, token) => { provider.resolveCompletionItem = (suggestion, token) => {
return this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion._id!, token).then(result => { return this._proxy.$resolveCompletionItem(handle, suggestion._id!, token).then(result => {
if (!result) { if (!result) {
return suggestion; return suggestion;
} }
@@ -7,7 +7,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext } from '../common/extHost.protocol'; import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext } from '../common/extHost.protocol';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
@@ -294,7 +294,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
} }
} }
async save(uri: URI): Promise<boolean> { async save(uri: URI, token: CancellationToken): Promise<boolean> {
return this._proxy.$saveNotebook(this._viewType, uri); return this._proxy.$saveNotebook(this._viewType, uri, token);
} }
} }
@@ -409,6 +409,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
name: item.name, name: item.name,
ctorDescriptor: new SyncDescriptor(TreeViewPane), ctorDescriptor: new SyncDescriptor(TreeViewPane),
when: ContextKeyExpr.deserialize(item.when), when: ContextKeyExpr.deserialize(item.when),
containerIcon: viewContainer?.icon,
canToggleVisibility: true, canToggleVisibility: true,
canMoveView: true, canMoveView: true,
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name), treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name),
@@ -327,7 +327,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// namespace: languages // namespace: languages
const languages: typeof vscode.languages = { const languages: typeof vscode.languages = {
createDiagnosticCollection(name?: string): vscode.DiagnosticCollection { createDiagnosticCollection(name?: string): vscode.DiagnosticCollection {
return extHostDiagnostics.createDiagnosticCollection(name); return extHostDiagnostics.createDiagnosticCollection(extension.identifier, name);
}, },
get onDidChangeDiagnostics() { get onDidChangeDiagnostics() {
return extHostDiagnostics.onDidChangeDiagnostics; return extHostDiagnostics.onDidChangeDiagnostics;
@@ -923,10 +923,22 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// namespace: notebook // namespace: notebook
const notebook: typeof vscode.notebook = { const notebook: typeof vscode.notebook = {
get onDidOpenNotebookDocument(): Event<vscode.NotebookDocument> {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidOpenNotebookDocument;
},
get onDidCloseNotebookDocument(): Event<vscode.NotebookDocument> {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidCloseNotebookDocument;
},
registerNotebookProvider: (viewType: string, provider: vscode.NotebookProvider) => { registerNotebookProvider: (viewType: string, provider: vscode.NotebookProvider) => {
checkProposedApiEnabled(extension); checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookProvider(extension, viewType, provider); return extHostNotebook.registerNotebookProvider(extension, viewType, provider);
}, },
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider);
},
registerNotebookOutputRenderer: (type: string, outputFilter: vscode.NotebookOutputSelector, renderer: vscode.NotebookOutputRenderer) => { registerNotebookOutputRenderer: (type: string, outputFilter: vscode.NotebookOutputSelector, renderer: vscode.NotebookOutputRenderer) => {
checkProposedApiEnabled(extension); checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer); return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer);
@@ -1318,7 +1318,7 @@ export interface ExtHostLanguageFeaturesShape {
$releaseDocumentSemanticTokens(handle: number, semanticColoringResultId: number): void; $releaseDocumentSemanticTokens(handle: number, semanticColoringResultId: number): void;
$provideDocumentRangeSemanticTokens(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<VSBuffer | null>; $provideDocumentRangeSemanticTokens(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<VSBuffer | null>;
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined>; $provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined>;
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined>; $resolveCompletionItem(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined>;
$releaseCompletionItems(handle: number, id: number): void; $releaseCompletionItems(handle: number, id: number): void;
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<ISignatureHelpDto | undefined>; $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<ISignatureHelpDto | undefined>;
$releaseSignatureHelp(handle: number, id: number): void; $releaseSignatureHelp(handle: number, id: number): void;
@@ -1545,7 +1545,7 @@ export interface INotebookEditorPropertiesChangeData {
export interface ExtHostNotebookShape { export interface ExtHostNotebookShape {
$resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined>; $resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined>;
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>; $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
$saveNotebook(viewType: string, uri: UriComponents): Promise<boolean>; $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>; $updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>;
$destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>; $destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>;
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void; $acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
@@ -13,25 +13,21 @@ import * as converter from './extHostTypeConverters';
import { mergeSort } from 'vs/base/common/arrays'; import { mergeSort } from 'vs/base/common/arrays';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { ResourceMap } from 'vs/base/common/map';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export class DiagnosticCollection implements vscode.DiagnosticCollection { export class DiagnosticCollection implements vscode.DiagnosticCollection {
private readonly _name: string;
private readonly _owner: string;
private readonly _maxDiagnosticsPerFile: number;
private readonly _onDidChangeDiagnostics: Emitter<(vscode.Uri | string)[]>;
private readonly _proxy: MainThreadDiagnosticsShape | undefined;
private _isDisposed = false; private _isDisposed = false;
private _data = new Map<string, vscode.Diagnostic[]>(); private _data = new ResourceMap<vscode.Diagnostic[]>();
constructor(name: string, owner: string, maxDiagnosticsPerFile: number, proxy: MainThreadDiagnosticsShape | undefined, onDidChangeDiagnostics: Emitter<(vscode.Uri | string)[]>) { constructor(
this._name = name; private readonly _name: string,
this._owner = owner; private readonly _owner: string,
this._maxDiagnosticsPerFile = maxDiagnosticsPerFile; private readonly _maxDiagnosticsPerFile: number,
this._proxy = proxy; private readonly _proxy: MainThreadDiagnosticsShape | undefined,
this._onDidChangeDiagnostics = onDidChangeDiagnostics; private readonly _onDidChangeDiagnostics: Emitter<vscode.Uri[]>
} ) { }
dispose(): void { dispose(): void {
if (!this._isDisposed) { if (!this._isDisposed) {
@@ -73,7 +69,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
} }
// update single row // update single row
this._data.set(first.toString(), diagnostics.slice()); this._data.set(first, diagnostics.slice());
toSync = [first]; toSync = [first];
} else if (Array.isArray(first)) { } else if (Array.isArray(first)) {
@@ -87,8 +83,8 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
for (const tuple of first) { for (const tuple of first) {
const [uri, diagnostics] = tuple; const [uri, diagnostics] = tuple;
if (!lastUri || uri.toString() !== lastUri.toString()) { if (!lastUri || uri.toString() !== lastUri.toString()) {
if (lastUri && this._data.get(lastUri.toString())!.length === 0) { if (lastUri && this._data.get(lastUri)!.length === 0) {
this._data.delete(lastUri.toString()); this._data.delete(lastUri);
} }
lastUri = uri; lastUri = uri;
toSync.push(uri); toSync.push(uri);
@@ -120,7 +116,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
const entries: [URI, IMarkerData[]][] = []; const entries: [URI, IMarkerData[]][] = [];
for (let uri of toSync) { for (let uri of toSync) {
let marker: IMarkerData[] = []; let marker: IMarkerData[] = [];
const diagnostics = this._data.get(uri.toString()); const diagnostics = this._data.get(uri);
if (diagnostics) { if (diagnostics) {
// no more than N diagnostics per file // no more than N diagnostics per file
@@ -160,7 +156,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
delete(uri: vscode.Uri): void { delete(uri: vscode.Uri): void {
this._checkDisposed(); this._checkDisposed();
this._onDidChangeDiagnostics.fire([uri]); this._onDidChangeDiagnostics.fire([uri]);
this._data.delete(uri.toString()); this._data.delete(uri);
if (this._proxy) { if (this._proxy) {
this._proxy.$changeMany(this._owner, [[uri, undefined]]); this._proxy.$changeMany(this._owner, [[uri, undefined]]);
} }
@@ -177,15 +173,14 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
forEach(callback: (uri: URI, diagnostics: ReadonlyArray<vscode.Diagnostic>, collection: DiagnosticCollection) => any, thisArg?: any): void { forEach(callback: (uri: URI, diagnostics: ReadonlyArray<vscode.Diagnostic>, collection: DiagnosticCollection) => any, thisArg?: any): void {
this._checkDisposed(); this._checkDisposed();
this._data.forEach((value, key) => { this._data.forEach((value, uri) => {
const uri = URI.parse(key);
callback.apply(thisArg, [uri, this.get(uri), this]); callback.apply(thisArg, [uri, this.get(uri), this]);
}); });
} }
get(uri: URI): ReadonlyArray<vscode.Diagnostic> { get(uri: URI): ReadonlyArray<vscode.Diagnostic> {
this._checkDisposed(); this._checkDisposed();
const result = this._data.get(uri.toString()); const result = this._data.get(uri);
if (Array.isArray(result)) { if (Array.isArray(result)) {
return <ReadonlyArray<vscode.Diagnostic>>Object.freeze(result.slice(0)); return <ReadonlyArray<vscode.Diagnostic>>Object.freeze(result.slice(0));
} }
@@ -194,7 +189,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
has(uri: URI): boolean { has(uri: URI): boolean {
this._checkDisposed(); this._checkDisposed();
return Array.isArray(this._data.get(uri.toString())); return Array.isArray(this._data.get(uri));
} }
private _checkDisposed() { private _checkDisposed() {
@@ -221,7 +216,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
private readonly _proxy: MainThreadDiagnosticsShape; private readonly _proxy: MainThreadDiagnosticsShape;
private readonly _collections = new Map<string, DiagnosticCollection>(); private readonly _collections = new Map<string, DiagnosticCollection>();
private readonly _onDidChangeDiagnostics = new Emitter<(vscode.Uri | string)[]>(); private readonly _onDidChangeDiagnostics = new Emitter<vscode.Uri[]>();
static _debouncer(last: (vscode.Uri | string)[] | undefined, current: (vscode.Uri | string)[]): (vscode.Uri | string)[] { static _debouncer(last: (vscode.Uri | string)[] | undefined, current: (vscode.Uri | string)[]): (vscode.Uri | string)[] {
if (!last) { if (!last) {
@@ -257,8 +252,25 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics); this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics);
} }
createDiagnosticCollection(name?: string): vscode.DiagnosticCollection { createDiagnosticCollection(extensionId: ExtensionIdentifier, name?: string): vscode.DiagnosticCollection {
let { _collections, _proxy, _onDidChangeDiagnostics } = this;
const { _collections, _proxy, _onDidChangeDiagnostics, _logService } = this;
const loggingProxy = new class implements MainThreadDiagnosticsShape {
$changeMany(owner: string, entries: [UriComponents, IMarkerData[] | undefined][]): void {
_proxy.$changeMany(owner, entries);
_logService.trace('[DiagnosticCollection] change many (extension, owner, uris)', extensionId.value, owner, entries.length === 0 ? 'CLEARING' : entries);
}
$clear(owner: string): void {
_proxy.$clear(owner);
_logService.trace('[DiagnosticCollection] remove all (extension, owner)', extensionId.value, owner);
}
dispose(): void {
_proxy.dispose();
}
};
let owner: string; let owner: string;
if (!name) { if (!name) {
name = '_generated_diagnostic_collection_name_#' + ExtHostDiagnostics._idPool++; name = '_generated_diagnostic_collection_name_#' + ExtHostDiagnostics._idPool++;
@@ -274,7 +286,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
const result = new class extends DiagnosticCollection { const result = new class extends DiagnosticCollection {
constructor() { constructor() {
super(name!, owner, ExtHostDiagnostics._maxDiagnosticsPerFile, _proxy, _onDidChangeDiagnostics); super(name!, owner, ExtHostDiagnostics._maxDiagnosticsPerFile, loggingProxy, _onDidChangeDiagnostics);
_collections.set(owner, this); _collections.set(owner, this);
} }
dispose() { dispose() {
@@ -5,7 +5,6 @@
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { sequence } from 'vs/base/common/async';
import { illegalState } from 'vs/base/common/errors'; import { illegalState } from 'vs/base/common/errors';
import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
import { TextEdit } from 'vs/workbench/api/common/extHostTypes'; import { TextEdit } from 'vs/workbench/api/common/extHostTypes';
@@ -48,26 +47,27 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
}; };
} }
$participateInSave(data: UriComponents, reason: SaveReason): Promise<boolean[]> { async $participateInSave(data: UriComponents, reason: SaveReason): Promise<boolean[]> {
const resource = URI.revive(data); const resource = URI.revive(data);
const entries = this._callbacks.toArray();
let didTimeout = false; let didTimeout = false;
const didTimeoutHandle = setTimeout(() => didTimeout = true, this._thresholds.timeout); const didTimeoutHandle = setTimeout(() => didTimeout = true, this._thresholds.timeout);
const promise = sequence(entries.map(listener => { const results: boolean[] = [];
return () => { try {
for (let listener of [...this._callbacks]) { // copy to prevent concurrent modifications
if (didTimeout) { if (didTimeout) {
// timeout - no more listeners // timeout - no more listeners
return Promise.resolve(); break;
} }
const document = this._documents.getDocument(resource); const document = this._documents.getDocument(resource);
return this._deliverEventAsyncAndBlameBadListeners(listener, <any>{ document, reason: TextDocumentSaveReason.to(reason) }); const success = await this._deliverEventAsyncAndBlameBadListeners(listener, <any>{ document, reason: TextDocumentSaveReason.to(reason) });
}; results.push(success);
})); }
return promise.finally(() => clearTimeout(didTimeoutHandle)); } finally {
clearTimeout(didTimeoutHandle);
}
return results;
} }
private _deliverEventAsyncAndBlameBadListeners([listener, thisArg, extension]: Listener, stubEvent: vscode.TextDocumentWillSaveEvent): Promise<any> { private _deliverEventAsyncAndBlameBadListeners([listener, thisArg, extension]: Listener, stubEvent: vscode.TextDocumentWillSaveEvent): Promise<any> {
@@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { mixin } from 'vs/base/common/objects'; import { mixin } from 'vs/base/common/objects';
import type * as vscode from 'vscode'; import type * as vscode from 'vscode';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits } from 'vs/workbench/api/common/extHostTypes'; import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit } from 'vs/workbench/api/common/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/model'; import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes'; import * as modes from 'vs/editor/common/modes';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
@@ -676,6 +676,13 @@ class SemanticTokensPreviousResult {
) { } ) { }
} }
type RelaxedSemanticTokens = { readonly resultId?: string; readonly data: number[]; };
type RelaxedSemanticTokensEdit = { readonly start: number; readonly deleteCount: number; readonly data?: number[]; };
type RelaxedSemanticTokensEdits = { readonly resultId?: string; readonly edits: RelaxedSemanticTokensEdit[]; };
type ProvidedSemanticTokens = vscode.SemanticTokens | RelaxedSemanticTokens;
type ProvidedSemanticTokensEdits = vscode.SemanticTokensEdits | RelaxedSemanticTokensEdits;
export class DocumentSemanticTokensAdapter { export class DocumentSemanticTokensAdapter {
private readonly _previousResults: Map<number, SemanticTokensPreviousResult>; private readonly _previousResults: Map<number, SemanticTokensPreviousResult>;
@@ -696,13 +703,14 @@ export class DocumentSemanticTokensAdapter {
return this._provider.provideDocumentSemanticTokensEdits(doc, previousResult.resultId, token); return this._provider.provideDocumentSemanticTokensEdits(doc, previousResult.resultId, token);
} }
return this._provider.provideDocumentSemanticTokens(doc, token); return this._provider.provideDocumentSemanticTokens(doc, token);
}).then(value => { }).then((value: ProvidedSemanticTokens | ProvidedSemanticTokensEdits | null | undefined) => {
if (previousResult) { if (previousResult) {
this._previousResults.delete(previousResultId); this._previousResults.delete(previousResultId);
} }
if (!value) { if (!value) {
return null; return null;
} }
value = DocumentSemanticTokensAdapter._fixProvidedSemanticTokens(value);
return this._send(DocumentSemanticTokensAdapter._convertToEdits(previousResult, value), value); return this._send(DocumentSemanticTokensAdapter._convertToEdits(previousResult, value), value);
}); });
} }
@@ -711,12 +719,40 @@ export class DocumentSemanticTokensAdapter {
this._previousResults.delete(semanticColoringResultId); this._previousResults.delete(semanticColoringResultId);
} }
private static _isSemanticTokens(v: vscode.SemanticTokens | vscode.SemanticTokensEdits): v is vscode.SemanticTokens { private static _fixProvidedSemanticTokens(v: ProvidedSemanticTokens | ProvidedSemanticTokensEdits): vscode.SemanticTokens | vscode.SemanticTokensEdits {
return v && !!((v as vscode.SemanticTokens).data); if (DocumentSemanticTokensAdapter._isSemanticTokens(v)) {
if (DocumentSemanticTokensAdapter._isCorrectSemanticTokens(v)) {
return v;
}
return new SemanticTokens(new Uint32Array(v.data), v.resultId);
} else if (DocumentSemanticTokensAdapter._isSemanticTokensEdits(v)) {
if (DocumentSemanticTokensAdapter._isCorrectSemanticTokensEdits(v)) {
return v;
}
return new SemanticTokensEdits(v.edits.map(edit => new SemanticTokensEdit(edit.start, edit.deleteCount, edit.data ? new Uint32Array(edit.data) : edit.data as undefined)), v.resultId); // {{SQL CARBON EDIT}} strict-null-checks
}
return v;
} }
private static _isSemanticTokensEdits(v: vscode.SemanticTokens | vscode.SemanticTokensEdits): v is vscode.SemanticTokensEdits { private static _isSemanticTokens(v: ProvidedSemanticTokens | ProvidedSemanticTokensEdits): v is ProvidedSemanticTokens {
return v && Array.isArray((v as vscode.SemanticTokensEdits).edits); return v && !!((v as ProvidedSemanticTokens).data);
}
private static _isCorrectSemanticTokens(v: ProvidedSemanticTokens): v is vscode.SemanticTokens {
return (v.data instanceof Uint32Array);
}
private static _isSemanticTokensEdits(v: ProvidedSemanticTokens | ProvidedSemanticTokensEdits): v is ProvidedSemanticTokensEdits {
return v && Array.isArray((v as ProvidedSemanticTokensEdits).edits);
}
private static _isCorrectSemanticTokensEdits(v: ProvidedSemanticTokensEdits): v is vscode.SemanticTokensEdits {
for (const edit of v.edits) {
if (!(edit.data instanceof Uint32Array)) {
return false;
}
}
return true;
} }
private static _convertToEdits(previousResult: SemanticTokensPreviousResult | null | undefined, newResult: vscode.SemanticTokens | vscode.SemanticTokensEdits): vscode.SemanticTokens | vscode.SemanticTokensEdits { private static _convertToEdits(previousResult: SemanticTokensPreviousResult | null | undefined, newResult: vscode.SemanticTokens | vscode.SemanticTokensEdits): vscode.SemanticTokens | vscode.SemanticTokensEdits {
@@ -876,33 +912,30 @@ class SuggestAdapter {
for (let i = 0; i < list.items.length; i++) { for (let i = 0; i < list.items.length; i++) {
const item = list.items[i]; const item = list.items[i];
// check for bad completion item first // check for bad completion item first
if (this._validateCompletionItem(item, pos)) {
const dto = this._convertCompletionItem(item, [pid, i], insertRange, replaceRange); const dto = this._convertCompletionItem(item, [pid, i], insertRange, replaceRange);
completions.push(dto); completions.push(dto);
} }
}
return result; return result;
} }
async resolveCompletionItem(_resource: URI, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> { async resolveCompletionItem(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
if (typeof this._provider.resolveCompletionItem !== 'function') { if (typeof this._provider.resolveCompletionItem !== 'function') {
return Promise.resolve(undefined); return undefined;
} }
const item = this._cache.get(...id); const item = this._cache.get(...id);
if (!item) { if (!item) {
return Promise.resolve(undefined); return undefined;
} }
const pos = typeConvert.Position.to(position);
const _mustNotChange = SuggestAdapter._mustNotChangeHash(item); const _mustNotChange = SuggestAdapter._mustNotChangeHash(item);
const _mayNotChange = SuggestAdapter._mayNotChangeHash(item); const _mayNotChange = SuggestAdapter._mayNotChangeHash(item);
const resolvedItem = await asPromise(() => this._provider.resolveCompletionItem!(item, token)); const resolvedItem = await asPromise(() => this._provider.resolveCompletionItem!(item, token));
if (!resolvedItem || !this._validateCompletionItem(resolvedItem, pos)) { if (!resolvedItem) {
return undefined; return undefined;
} }
@@ -952,14 +985,14 @@ class SuggestAdapter {
// //
x: id, x: id,
// //
[extHostProtocol.ISuggestDataDtoField.label]: item.label, [extHostProtocol.ISuggestDataDtoField.label]: item.label ?? '',
[extHostProtocol.ISuggestDataDtoField.label2]: item.label2, [extHostProtocol.ISuggestDataDtoField.label2]: item.label2,
[extHostProtocol.ISuggestDataDtoField.kind]: item.kind !== undefined ? typeConvert.CompletionItemKind.from(item.kind) : undefined, [extHostProtocol.ISuggestDataDtoField.kind]: item.kind !== undefined ? typeConvert.CompletionItemKind.from(item.kind) : undefined,
[extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from), [extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
[extHostProtocol.ISuggestDataDtoField.detail]: item.detail, [extHostProtocol.ISuggestDataDtoField.detail]: item.detail,
[extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation), [extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
[extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText, [extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText !== item.label ? item.sortText : undefined,
[extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText, [extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText !== item.label ? item.filterText : undefined,
[extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect || undefined, [extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect || undefined,
[extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0, [extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
[extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters, [extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters,
@@ -1003,31 +1036,6 @@ class SuggestAdapter {
return result; return result;
} }
private _validateCompletionItem(item: vscode.CompletionItem, position: vscode.Position): boolean {
if (typeof item.label !== 'string' || item.label.length === 0) {
this._logService.warn('INVALID text edit -> must have at least a label');
return false;
}
if (Range.isRange(item.range)) {
if (!item.range.isSingleLine || item.range.start.line !== position.line) {
this._logService.trace('INVALID range -> must be single line and on the same line');
return false;
}
} else if (item.range) {
if (!item.range.inserting.isSingleLine || item.range.inserting.start.line !== position.line
|| !item.range.replacing.isSingleLine || item.range.replacing.start.line !== position.line
|| !item.range.inserting.start.isEqual(item.range.replacing.start)
|| !item.range.replacing.contains(item.range.inserting)
) {
this._logService.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range');
return false;
}
}
return true;
}
private static _mustNotChangeHash(item: vscode.CompletionItem) { private static _mustNotChangeHash(item: vscode.CompletionItem) {
const res = JSON.stringify([item.label, item.sortText, item.filterText, item.insertText, item.range]); const res = JSON.stringify([item.label, item.sortText, item.filterText, item.insertText, item.range]);
return res; return res;
@@ -1781,8 +1789,8 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined); return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined);
} }
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> { $resolveCompletionItem(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, id, token), undefined); return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(id, token), undefined);
} }
$releaseCompletionItems(handle: number, id: number): void { $releaseCompletionItems(handle: number, id: number): void {
+113 -11
View File
@@ -626,12 +626,13 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private readonly _proxy: MainThreadNotebookShape; private readonly _proxy: MainThreadNotebookShape;
private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription; }>(); private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription; }>();
private readonly _notebookContentProviders = new Map<string, { readonly provider: vscode.NotebookContentProvider, readonly extension: IExtensionDescription; }>();
private readonly _documents = new Map<string, ExtHostNotebookDocument>(); private readonly _documents = new Map<string, ExtHostNotebookDocument>();
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any> }>(); private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; }>();
private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>(); private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>();
private readonly _onDidChangeNotebookDocument = new Emitter<{ document: ExtHostNotebookDocument, changes: NotebookCellsChangedEvent[] }>(); private readonly _onDidChangeNotebookDocument = new Emitter<{ document: ExtHostNotebookDocument, changes: NotebookCellsChangedEvent[]; }>();
readonly onDidChangeNotebookDocument: Event<{ document: ExtHostNotebookDocument, changes: NotebookCellsChangedEvent[] }> = this._onDidChangeNotebookDocument.event; readonly onDidChangeNotebookDocument: Event<{ document: ExtHostNotebookDocument, changes: NotebookCellsChangedEvent[]; }> = this._onDidChangeNotebookDocument.event;
private _outputDisplayOrder: INotebookDisplayOrder | undefined; private _outputDisplayOrder: INotebookDisplayOrder | undefined;
@@ -651,6 +652,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return this._activeNotebookEditor; return this._activeNotebookEditor;
} }
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors) { constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook); this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
@@ -718,7 +724,82 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}); });
} }
registerNotebookContentProvider(
extension: IExtensionDescription,
viewType: string,
provider: vscode.NotebookContentProvider,
): vscode.Disposable {
if (this._notebookProviders.has(viewType)) {
throw new Error(`Notebook provider for '${viewType}' already registered`);
}
this._notebookContentProviders.set(viewType, { extension, provider });
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType);
return new VSCodeDisposable(() => {
this._notebookContentProviders.delete(viewType);
this._proxy.$unregisterNotebookProvider(viewType);
});
}
async _resolveNotebookFromContentProvider(viewType: string, uri: UriComponents): Promise<number | undefined> {
let provider = this._notebookContentProviders.get(viewType);
if (provider) {
const revivedUri = URI.revive(uri);
if (!this._documents.has(revivedUri.toString())) {
let document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, viewType, revivedUri, this);
await this._proxy.$createNotebookDocument(
document.handle,
viewType,
uri
);
this._documents.set(revivedUri.toString(), document);
}
const onDidReceiveMessage = new Emitter<any>();
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
revivedUri,
this._proxy,
onDidReceiveMessage,
this._documents.get(revivedUri.toString())!,
this._documentsAndEditors
);
this._editors.set(revivedUri.toString(), { editor, onDidReceiveMessage });
const data = await provider.provider.openNotebook(revivedUri);
editor.document.languages = data.languages;
editor.document.metadata = {
...notebookDocumentMetadataDefaults,
...data.metadata
};
await editor.edit(editBuilder => {
for (let i = 0; i < data.cells.length; i++) {
const cell = data.cells[i];
editBuilder.insert(0, cell.source, cell.language, cell.cellKind, cell.outputs, cell.metadata);
}
});
this._onDidOpenNotebookDocument.fire(editor.document);
return editor.document.handle;
} else {
return Promise.resolve(undefined);
}
}
async $resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined> { async $resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined> {
let notebookFromNotebookContentProvider = await this._resolveNotebookFromContentProvider(viewType, uri);
if (notebookFromNotebookContentProvider !== undefined) {
return notebookFromNotebookContentProvider;
}
let provider = this._notebookProviders.get(viewType); let provider = this._notebookProviders.get(viewType);
if (provider) { if (provider) {
@@ -755,25 +836,45 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
} }
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> { async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
let provider = this._notebookProviders.get(viewType);
if (!provider) {
return;
}
let document = this._documents.get(URI.revive(uri).toString()); let document = this._documents.get(URI.revive(uri).toString());
if (!document) { if (!document) {
return; return;
} }
if (this._notebookContentProviders.has(viewType)) {
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
return this._notebookContentProviders.get(viewType)!.provider.executeCell(document, cell, token);
}
let provider = this._notebookProviders.get(viewType);
if (!provider) {
return;
}
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined; let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
return provider.provider.executeCell(document!, cell, token); return provider.provider.executeCell(document!, cell, token);
} }
async $saveNotebook(viewType: string, uri: UriComponents): Promise<boolean> { async $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean> {
let provider = this._notebookProviders.get(viewType);
let document = this._documents.get(URI.revive(uri).toString()); let document = this._documents.get(URI.revive(uri).toString());
if (!document) {
return false;
}
if (this._notebookContentProviders.has(viewType)) {
try {
await this._notebookContentProviders.get(viewType)!.provider.saveNotebook(document, token);
} catch (e) {
return false;
}
return true;
}
let provider = this._notebookProviders.get(viewType);
if (provider && document) { if (provider && document) {
return await provider.provider.save(document); return await provider.provider.save(document);
@@ -799,6 +900,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
if (document) { if (document) {
document.dispose(); document.dispose();
this._documents.delete(URI.revive(uri).toString()); this._documents.delete(URI.revive(uri).toString());
this._onDidCloseNotebookDocument.fire(document);
} }
let editor = this._editors.get(URI.revive(uri).toString()); let editor = this._editors.get(URI.revive(uri).toString());
@@ -159,8 +159,8 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
// ---- workspace folder picker // ---- workspace folder picker
showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Promise<WorkspaceFolder | undefined> { async showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Promise<WorkspaceFolder | undefined> {
return this._commands.executeCommand<WorkspaceFolder>('_workbench.pickWorkspaceFolder', [options]).then(async (selectedFolder: WorkspaceFolder) => { const selectedFolder = await this._commands.executeCommand<WorkspaceFolder>('_workbench.pickWorkspaceFolder', [options]);
if (!selectedFolder) { if (!selectedFolder) {
return undefined; return undefined;
} }
@@ -168,8 +168,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
if (!workspaceFolders) { if (!workspaceFolders) {
return undefined; return undefined;
} }
return workspaceFolders.filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]; return workspaceFolders.find(folder => folder.uri.toString() === selectedFolder.uri.toString());
});
} }
// ---- QuickInput // ---- QuickInput
@@ -11,7 +11,6 @@ import { nullExtensionDescription } from 'vs/workbench/services/extensions/commo
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { endsWith } from 'vs/base/common/strings';
import { IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl'; import { IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -196,7 +195,7 @@ class KeytarNodeModuleFactory implements INodeModuleFactory {
return undefined; return undefined;
} }
const sep = length - 7; const sep = length - 7;
if ((name.charAt(sep) === '/' || name.charAt(sep) === '\\') && endsWith(name, 'keytar')) { if ((name.charAt(sep) === '/' || name.charAt(sep) === '\\') && name.endsWith('keytar')) {
name = name.replace(/\\/g, '/'); name = name.replace(/\\/g, '/');
if (this.alternativeNames.has(name)) { if (this.alternativeNames.has(name)) {
return 'keytar'; return 'keytar';
@@ -155,7 +155,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
} }
} }
type Root = null | undefined; export type Root = null | undefined | void; // {{SQL CARBON EDIT}} export interface
type TreeData<T> = { message: boolean, element: T | Root | false }; type TreeData<T> = { message: boolean, element: T | Root | false };
export interface TreeNode extends IDisposable { // {{SQL CARBON EDIT}} export interface export interface TreeNode extends IDisposable { // {{SQL CARBON EDIT}} export interface
@@ -10,7 +10,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { forEach } from 'vs/base/common/collections'; import { forEach } from 'vs/base/common/collections';
import { IExtensionPointUser, ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { IExtensionPointUser, ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { MenuId, MenuRegistry, ILocalizedString, IMenuItem } from 'vs/platform/actions/common/actions'; import { MenuId, MenuRegistry, ILocalizedString, IMenuItem, ICommandAction } from 'vs/platform/actions/common/actions';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { DisposableStore } from 'vs/base/common/lifecycle'; import { DisposableStore } from 'vs/base/common/lifecycle';
import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ThemeIcon } from 'vs/platform/theme/common/themeService';
@@ -387,7 +387,7 @@ export const commandsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<
commandsExtensionPoint.setHandler(extensions => { commandsExtensionPoint.setHandler(extensions => {
function handleCommand(userFriendlyCommand: schema.IUserFriendlyCommand, extension: IExtensionPointUser<any>) { function handleCommand(userFriendlyCommand: schema.IUserFriendlyCommand, extension: IExtensionPointUser<any>, bucket: ICommandAction[]) {
if (!schema.isValidCommand(userFriendlyCommand, extension.collector)) { if (!schema.isValidCommand(userFriendlyCommand, extension.collector)) {
return; return;
@@ -411,29 +411,30 @@ commandsExtensionPoint.setHandler(extensions => {
if (MenuRegistry.getCommand(command)) { if (MenuRegistry.getCommand(command)) {
extension.collector.info(localize('dup', "Command `{0}` appears multiple times in the `commands` section.", userFriendlyCommand.command)); extension.collector.info(localize('dup', "Command `{0}` appears multiple times in the `commands` section.", userFriendlyCommand.command));
} }
const registration = MenuRegistry.addCommand({ bucket.push({
id: command, id: command,
title, title,
category, category,
precondition: ContextKeyExpr.deserialize(enablement), precondition: ContextKeyExpr.deserialize(enablement),
icon: absoluteIcon icon: absoluteIcon
}); });
_commandRegistrations.add(registration);
} }
// remove all previous command registrations // remove all previous command registrations
_commandRegistrations.clear(); _commandRegistrations.clear();
const newCommands: ICommandAction[] = [];
for (const extension of extensions) { for (const extension of extensions) {
const { value } = extension; const { value } = extension;
if (Array.isArray(value)) { if (Array.isArray(value)) {
for (const command of value) { for (const command of value) {
handleCommand(command, extension); handleCommand(command, extension, newCommands);
} }
} else { } else {
handleCommand(value, extension); handleCommand(value, extension, newCommands);
} }
} }
_commandRegistrations.add(MenuRegistry.addCommands(newCommands));
}); });
const _menuRegistrations = new DisposableStore(); const _menuRegistrations = new DisposableStore();
@@ -446,6 +447,8 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM
// remove all previous menu registrations // remove all previous menu registrations
_menuRegistrations.clear(); _menuRegistrations.clear();
const items: { id: MenuId, item: IMenuItem }[] = [];
for (let extension of extensions) { for (let extension of extensions) {
const { value, collector } = extension; const { value, collector } = extension;
@@ -467,7 +470,7 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM
for (let item of entry.value) { for (let item of entry.value) {
let command = MenuRegistry.getCommand(item.command); let command = MenuRegistry.getCommand(item.command);
let alt = item.alt && MenuRegistry.getCommand(item.alt); let alt = item.alt && MenuRegistry.getCommand(item.alt) || undefined;
if (!command) { if (!command) {
collector.error(localize('missing.command', "Menu item references a command `{0}` which is not defined in the 'commands' section.", item.command)); collector.error(localize('missing.command', "Menu item references a command `{0}` which is not defined in the 'commands' section.", item.command));
@@ -492,15 +495,19 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM
} }
} }
const registration = MenuRegistry.appendMenuItem(menu, { items.push({
id: menu,
item: {
command, command,
alt, alt,
group, group,
order, order,
when: ContextKeyExpr.deserialize(item.when) when: ContextKeyExpr.deserialize(item.when)
} as IMenuItem);
_menuRegistrations.add(registration);
} }
}); });
} }
}); });
}
_menuRegistrations.add(MenuRegistry.appendMenuItems(items));
});
@@ -6,7 +6,6 @@
import { createApiFactoryAndRegisterActors } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} replace with ours import { createApiFactoryAndRegisterActors } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} replace with ours
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { endsWith } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
@@ -79,5 +78,5 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
} }
function ensureSuffix(path: string, suffix: string): string { function ensureSuffix(path: string, suffix: string): string {
return endsWith(path, suffix) ? path : path + suffix; return path.endsWith(suffix) ? path : path + suffix;
} }
@@ -487,7 +487,7 @@ export class ResetViewLocationsAction extends Action {
} }
async run(): Promise<void> { async run(): Promise<void> {
this.viewDescriptorService.getViewContainers().forEach(viewContainer => { this.viewDescriptorService.viewContainers.forEach(viewContainer => {
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
viewContainerModel.allViewDescriptors.forEach(viewDescriptor => { viewContainerModel.allViewDescriptors.forEach(viewDescriptor => {
@@ -596,7 +596,7 @@ export class MoveFocusedViewAction extends Action {
}); });
} }
const pinnedViewlets = this.activityBarService.getPinnedViewletIds(); const pinnedViewlets = this.activityBarService.getPinnedViewContainerIds();
items.push(...pinnedViewlets items.push(...pinnedViewlets
.filter(viewletId => { .filter(viewletId => {
if (viewletId === this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) { if (viewletId === this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) {
@@ -7,7 +7,6 @@ import * as nls from 'vs/nls';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
import * as resources from 'vs/base/common/resources'; import * as resources from 'vs/base/common/resources';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { CommandsRegistry } from 'vs/platform/commands/common/commands';
@@ -19,6 +18,7 @@ import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService'; import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService'; import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder'; export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder';
export const ADD_ROOT_FOLDER_LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace..."); export const ADD_ROOT_FOLDER_LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace...");
@@ -55,7 +55,8 @@ CommandsRegistry.registerCommand({
CommandsRegistry.registerCommand({ CommandsRegistry.registerCommand({
id: ADD_ROOT_FOLDER_COMMAND_ID, id: ADD_ROOT_FOLDER_COMMAND_ID,
handler: async (accessor) => { handler: async (accessor) => {
const viewletService = accessor.get(IViewletService); const viewDescriptorService = accessor.get(IViewDescriptorService);
const viewsService = accessor.get(IViewsService);
const workspaceEditingService = accessor.get(IWorkspaceEditingService); const workspaceEditingService = accessor.get(IWorkspaceEditingService);
const dialogsService = accessor.get(IFileDialogService); const dialogsService = accessor.get(IFileDialogService);
const folders = await dialogsService.showOpenDialog({ const folders = await dialogsService.showOpenDialog({
@@ -71,7 +72,7 @@ CommandsRegistry.registerCommand({
} }
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: resources.removeTrailingPathSeparator(folder) }))); await workspaceEditingService.addFolders(folders.map(folder => ({ uri: resources.removeTrailingPathSeparator(folder) })));
await viewletService.openViewlet(viewletService.getDefaultViewletId(), true); await viewsService.openViewContainer(viewDescriptorService.getDefaultViewContainer(ViewContainerLocation.Sidebar)!.id, true);
} }
}); });
+2 -3
View File
@@ -15,7 +15,6 @@ import { trackFocus, Dimension } from 'vs/base/browser/dom';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { assertIsDefined } from 'vs/base/common/types'; import { assertIsDefined } from 'vs/base/common/types';
import { find } from 'vs/base/common/arrays';
/** /**
* Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite
@@ -256,7 +255,7 @@ export abstract class CompositeRegistry<T extends Composite> extends Disposable
private readonly _onDidDeregister = this._register(new Emitter<CompositeDescriptor<T>>()); private readonly _onDidDeregister = this._register(new Emitter<CompositeDescriptor<T>>());
readonly onDidDeregister = this._onDidDeregister.event; readonly onDidDeregister = this._onDidDeregister.event;
private composites: CompositeDescriptor<T>[] = []; private readonly composites: CompositeDescriptor<T>[] = [];
protected registerComposite(descriptor: CompositeDescriptor<T>): void { protected registerComposite(descriptor: CompositeDescriptor<T>): void {
if (this.compositeById(descriptor.id)) { if (this.compositeById(descriptor.id)) {
@@ -286,6 +285,6 @@ export abstract class CompositeRegistry<T extends Composite> extends Disposable
} }
private compositeById(id: string): CompositeDescriptor<T> | undefined { private compositeById(id: string): CompositeDescriptor<T> | undefined {
return find(this.composites, composite => composite.id === id); return this.composites.find(composite => composite.id === id);
} }
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { find, insert } from 'vs/base/common/arrays'; import { insert } from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
export interface IEditorDescriptor { export interface IEditorDescriptor {
@@ -154,7 +154,7 @@ class EditorRegistry implements IEditorRegistry {
} }
getEditorById(editorId: string): EditorDescriptor | undefined { getEditorById(editorId: string): EditorDescriptor | undefined {
return find(this.editors, editor => editor.getId() === editorId); return this.editors.find(editor => editor.getId() === editorId);
} }
getEditors(): readonly EditorDescriptor[] { getEditors(): readonly EditorDescriptor[] {
+8 -5
View File
@@ -43,6 +43,7 @@ import { WINDOW_ACTIVE_BORDER, WINDOW_INACTIVE_BORDER } from 'vs/workbench/commo
import { LineNumbersType } from 'vs/editor/common/config/editorOptions'; import { LineNumbersType } from 'vs/editor/common/config/editorOptions';
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart'; import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
export enum Settings { export enum Settings {
ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible', ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible',
@@ -171,6 +172,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
private panelService!: IPanelService; private panelService!: IPanelService;
private titleService!: ITitleService; private titleService!: ITitleService;
private viewletService!: IViewletService; private viewletService!: IViewletService;
private viewDescriptorService!: IViewDescriptorService;
private contextService!: IWorkspaceContextService; private contextService!: IWorkspaceContextService;
private backupFileService!: IBackupFileService; private backupFileService!: IBackupFileService;
private notificationService!: INotificationService; private notificationService!: INotificationService;
@@ -255,6 +257,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.editorGroupService = accessor.get(IEditorGroupsService); this.editorGroupService = accessor.get(IEditorGroupsService);
this.panelService = accessor.get(IPanelService); this.panelService = accessor.get(IPanelService);
this.viewletService = accessor.get(IViewletService); this.viewletService = accessor.get(IViewletService);
this.viewDescriptorService = accessor.get(IViewDescriptorService);
this.titleService = accessor.get(ITitleService); this.titleService = accessor.get(ITitleService);
this.notificationService = accessor.get(INotificationService); this.notificationService = accessor.get(INotificationService);
accessor.get(IStatusbarService); // not used, but called to ensure instantiated accessor.get(IStatusbarService); // not used, but called to ensure instantiated
@@ -489,11 +492,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (!this.state.sideBar.hidden) { if (!this.state.sideBar.hidden) {
// Only restore last viewlet if window was reloaded or we are in development mode // Only restore last viewlet if window was reloaded or we are in development mode
let viewletToRestore: string; let viewletToRestore: string | undefined;
if (!this.environmentService.isBuilt || lifecycleService.startupKind === StartupKind.ReloadedWindow || isWeb) { if (!this.environmentService.isBuilt || lifecycleService.startupKind === StartupKind.ReloadedWindow || isWeb) {
viewletToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, this.viewletService.getDefaultViewletId()); viewletToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, this.viewDescriptorService.getDefaultViewContainer(ViewContainerLocation.Sidebar)?.id);
} else { } else {
viewletToRestore = this.viewletService.getDefaultViewletId(); viewletToRestore = this.viewDescriptorService.getDefaultViewContainer(ViewContainerLocation.Sidebar)?.id;
} }
if (viewletToRestore) { if (viewletToRestore) {
@@ -639,7 +642,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
} }
if (sidebarState.length) { if (sidebarState.length) {
storageService.store(ActivitybarPart.PINNED_VIEWLETS, JSON.stringify(sidebarState), StorageScope.GLOBAL); storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, JSON.stringify(sidebarState), StorageScope.GLOBAL);
} }
} }
} }
@@ -1344,7 +1347,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (viewletToOpen) { if (viewletToOpen) {
const viewlet = this.viewletService.openViewlet(viewletToOpen, true); const viewlet = this.viewletService.openViewlet(viewletToOpen, true);
if (!viewlet) { if (!viewlet) {
this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true); this.viewletService.openViewlet(this.viewDescriptorService.getDefaultViewContainer(ViewContainerLocation.Sidebar)?.id, true);
} }
} }
} }
-1
View File
@@ -19,7 +19,6 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
backdrop-filter: brightness(97%) blur(2px); backdrop-filter: brightness(97%) blur(2px);
pointer-events: none;
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
transition: opacity .5s, visibility .5s; transition: opacity .5s, visibility .5s;
@@ -11,7 +11,6 @@ import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch
import { Action, IAction } from 'vs/base/common/actions'; import { Action, IAction } from 'vs/base/common/actions';
import { KeyCode } from 'vs/base/common/keyCodes'; import { KeyCode } from 'vs/base/common/keyCodes';
import { dispose } from 'vs/base/common/lifecycle'; import { dispose } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { SyncActionDescriptor, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { SyncActionDescriptor, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
@@ -19,7 +18,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { IActivity } from 'vs/workbench/common/activity'; import { IActivity } from 'vs/workbench/common/activity';
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme';
@@ -30,9 +28,8 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
import { Codicon } from 'vs/base/common/codicons'; import { Codicon } from 'vs/base/common/codicons';
import { isString } from 'vs/base/common/types';
export class ViewletActivityAction extends ActivityAction { export class ViewContainerActivityAction extends ActivityAction {
private static readonly preventDoubleClickDelay = 300; private static readonly preventDoubleClickDelay = 300;
@@ -48,7 +45,6 @@ export class ViewletActivityAction extends ActivityAction {
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@ITelemetryService telemetryService: ITelemetryService @ITelemetryService telemetryService: ITelemetryService
) { ) {
ViewletActivityAction.generateIconCSS(activity);
super(activity); super(activity);
this.lastRun = 0; this.lastRun = 0;
@@ -57,23 +53,7 @@ export class ViewletActivityAction extends ActivityAction {
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
} }
private static generateIconCSS(activity: IActivity): void { updateActivity(activity: IActivity): void {
if (activity.iconUrl) {
activity.cssClass = activity.cssClass || `activity-${activity.id.replace(/\./g, '-')}`;
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${activity.cssClass}`;
DOM.createCSSRule(iconClass, `
mask: ${DOM.asCSSUrl(activity.iconUrl)} no-repeat 50% 50%;
mask-size: 24px;
-webkit-mask: ${DOM.asCSSUrl(activity.iconUrl)} no-repeat 50% 50%;
-webkit-mask-size: 24px;
`);
}
}
setActivity(activity: IActivity): void {
if (activity.iconUrl && this.activity.cssClass !== activity.cssClass) {
ViewletActivityAction.generateIconCSS(activity);
}
this.activity = activity; this.activity = activity;
} }
@@ -84,7 +64,7 @@ export class ViewletActivityAction extends ActivityAction {
// prevent accident trigger on a doubleclick (to help nervous people) // prevent accident trigger on a doubleclick (to help nervous people)
const now = Date.now(); const now = Date.now();
if (now > this.lastRun /* https://github.com/Microsoft/vscode/issues/25830 */ && now - this.lastRun < ViewletActivityAction.preventDoubleClickDelay) { if (now > this.lastRun /* https://github.com/Microsoft/vscode/issues/25830 */ && now - this.lastRun < ViewContainerActivityAction.preventDoubleClickDelay) {
return; return;
} }
this.lastRun = now; this.lastRun = now;
@@ -113,30 +93,6 @@ export class ViewletActivityAction extends ActivityAction {
} }
} }
export class ToggleViewletAction extends Action {
constructor(
private _viewlet: ViewletDescriptor,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IViewletService private readonly viewletService: IViewletService
) {
super(_viewlet.id, _viewlet.name);
}
async run(): Promise<void> {
const sideBarVisible = this.layoutService.isVisible(Parts.SIDEBAR_PART);
const activeViewlet = this.viewletService.getActiveViewlet();
// Hide sidebar if selected viewlet already visible
if (sideBarVisible && activeViewlet?.getId() === this._viewlet.id) {
this.layoutService.setSideBarHidden(true);
return;
}
await this.viewletService.openViewlet(this._viewlet.id, true);
}
}
export class AccountsActionViewItem extends ActivityActionViewItem { export class AccountsActionViewItem extends ActivityActionViewItem {
constructor( constructor(
action: ActivityAction, action: ActivityAction,
@@ -248,23 +204,7 @@ export class GlobalActivityActionViewItem extends ActivityActionViewItem {
} }
} }
export class PlaceHolderViewletActivityAction extends ViewletActivityAction { export class PlaceHolderViewContainerActivityAction extends ViewContainerActivityAction { }
constructor(
id: string,
icon: URI | string | undefined,
@IViewletService viewletService: IViewletService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@ITelemetryService telemetryService: ITelemetryService
) {
super({
id,
name: id,
iconUrl: URI.isUri(icon) ? icon : undefined,
cssClass: isString(icon) ? icon : undefined
}, viewletService, layoutService, telemetryService);
}
}
export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinnedAction { export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinnedAction {
@@ -289,16 +229,16 @@ class SwitchSideBarViewAction extends Action {
} }
async run(offset: number): Promise<void> { async run(offset: number): Promise<void> {
const pinnedViewletIds = this.activityBarService.getPinnedViewletIds(); const visibleViewletIds = this.activityBarService.getVisibleViewContainerIds();
const activeViewlet = this.viewletService.getActiveViewlet(); const activeViewlet = this.viewletService.getActiveViewlet();
if (!activeViewlet) { if (!activeViewlet) {
return; return;
} }
let targetViewletId: string | undefined; let targetViewletId: string | undefined;
for (let i = 0; i < pinnedViewletIds.length; i++) { for (let i = 0; i < visibleViewletIds.length; i++) {
if (pinnedViewletIds[i] === activeViewlet.getId()) { if (visibleViewletIds[i] === activeViewlet.getId()) {
targetViewletId = pinnedViewletIds[(i + pinnedViewletIds.length + offset) % pinnedViewletIds.length]; targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + offset) % visibleViewletIds.length];
break; break;
} }
} }
@@ -8,8 +8,7 @@ import * as nls from 'vs/nls';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { GLOBAL_ACTIVITY_ID, IActivity } from 'vs/workbench/common/activity'; import { GLOBAL_ACTIVITY_ID, IActivity } from 'vs/workbench/common/activity';
import { Part } from 'vs/workbench/browser/part'; import { Part } from 'vs/workbench/browser/part';
import { GlobalActivityActionViewItem, ViewletActivityAction, ToggleViewletAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewletActivityAction, AccountsActionViewItem, HomeAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActionViewItem, HomeAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService'; import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -19,15 +18,13 @@ import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeServic
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar'; import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
import { Dimension, addClass, removeNode } from 'vs/base/browser/dom'; import { Dimension, addClass, removeNode, createCSSRule, asCSSUrl } from 'vs/base/browser/dom';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions'; import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { IViewDescriptorService, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewContainerModel, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views';
import { IViewDescriptorService, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewContainerModel, ViewContainerLocation } from 'vs/workbench/common/views';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { isUndefinedOrNull, assertIsDefined, isString } from 'vs/base/common/types'; import { isUndefinedOrNull, assertIsDefined, isString } from 'vs/base/common/types';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@@ -42,8 +39,10 @@ import { getUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSy
import { IProductService } from 'vs/platform/product/common/productService'; import { IProductService } from 'vs/platform/product/common/productService';
import { Before2D } from 'vs/workbench/browser/dnd'; import { Before2D } from 'vs/workbench/browser/dnd';
import { Codicon, iconRegistry } from 'vs/base/common/codicons'; import { Codicon, iconRegistry } from 'vs/base/common/codicons';
import { Action } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
interface IPlaceholderViewlet { interface IPlaceholderViewContainer {
id: string; id: string;
name?: string; name?: string;
iconUrl?: UriComponents; iconUrl?: UriComponents;
@@ -51,14 +50,14 @@ interface IPlaceholderViewlet {
views?: { when?: string }[]; views?: { when?: string }[];
} }
interface IPinnedViewlet { interface IPinnedViewContainer {
id: string; id: string;
pinned: boolean; pinned: boolean;
order?: number; order?: number;
visible: boolean; visible: boolean;
} }
interface ICachedViewlet { interface ICachedViewContainer {
id: string; id: string;
name?: string; name?: string;
icon?: URI | string; icon?: URI | string;
@@ -73,8 +72,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
_serviceBrand: undefined; _serviceBrand: undefined;
private static readonly ACTION_HEIGHT = 48; private static readonly ACTION_HEIGHT = 48;
static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets2'; static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2';
private static readonly PLACEHOLDER_VIEWLETS = 'workbench.activity.placeholderViewlets'; private static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.activity.placeholderViewlets';
//#region IView //#region IView
@@ -99,18 +98,20 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private globalActivityActionBar: ActionBar | undefined; private globalActivityActionBar: ActionBar | undefined;
private readonly globalActivity: ICompositeActivity[] = []; private readonly globalActivity: ICompositeActivity[] = [];
private readonly cachedViewlets: ICachedViewlet[] = []; private readonly cachedViewContainers: ICachedViewContainer[] = [];
private readonly compositeActions = new Map<string, { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction }>(); private readonly compositeActions = new Map<string, { activityAction: ViewContainerActivityAction, pinnedAction: ToggleCompositePinnedAction }>();
private readonly viewletDisposables = new Map<string, IDisposable>(); private readonly viewContainerDisposables = new Map<string, IDisposable>();
private readonly location = ViewContainerLocation.Sidebar;
constructor( constructor(
@IViewletService private readonly viewletService: IViewletService,
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@IStorageService private readonly storageService: IStorageService, @IStorageService private readonly storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService, @IExtensionService private readonly extensionService: IExtensionService,
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
@IViewsService private readonly viewsService: IViewsService,
@IContextKeyService private readonly contextKeyService: IContextKeyService, @IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@@ -119,27 +120,27 @@ export class ActivitybarPart extends Part implements IActivityBarService {
) { ) {
super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
storageKeysSyncRegistryService.registerStorageKey({ key: ActivitybarPart.PINNED_VIEWLETS, version: 1 }); storageKeysSyncRegistryService.registerStorageKey({ key: ActivitybarPart.PINNED_VIEW_CONTAINERS, version: 1 });
this.migrateFromOldCachedViewletsValue(); this.migrateFromOldCachedViewContainersValue();
this.cachedViewlets = this.getCachedViewlets(); this.cachedViewContainers = this.getCachedViewContainers();
for (const cachedViewlet of this.cachedViewlets) { for (const cachedViewContainer of this.cachedViewContainers) {
if (environmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered. if (environmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered.
|| this.shouldBeHidden(cachedViewlet.id, cachedViewlet) || this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer)
) { ) {
cachedViewlet.visible = false; cachedViewContainer.visible = false;
} }
} }
const cachedItems = this.cachedViewlets const cachedItems = this.cachedViewContainers
.map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned })); .map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned }));
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, {
icon: true, icon: true,
orientation: ActionsOrientation.VERTICAL, orientation: ActionsOrientation.VERTICAL,
openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), openComposite: (compositeId: string) => this.viewsService.openViewContainer(compositeId, true),
getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction, getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction,
getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction, getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction,
getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, assertIsDefined(this.viewletService.getViewlet(compositeId))), getOnCompositeClickAction: (compositeId: string) => new Action(compositeId, '', '', true, () => this.viewsService.isViewContainerVisible(compositeId) ? Promise.resolve(this.viewsService.closeViewContainer(compositeId)) : this.viewsService.openViewContainer(compositeId)),
getContextMenuActions: () => { getContextMenuActions: () => {
const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService); const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService);
const actions = []; const actions = [];
@@ -152,10 +153,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
return actions; return actions;
}, },
getContextMenuActionsForComposite: () => [], getContextMenuActionsForComposite: () => [],
getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(), getDefaultCompositeId: () => this.viewDescriptorService.getDefaultViewContainer(this.location)!.id,
hidePart: () => this.layoutService.setSideBarHidden(true), hidePart: () => this.layoutService.setSideBarHidden(true),
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar, dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar,
(id: string, focus?: boolean) => this.viewletService.openViewlet(id, focus), (id: string, focus?: boolean) => this.viewsService.openViewContainer(id, focus),
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore) (from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore)
), ),
compositeSize: 52, compositeSize: 52,
@@ -163,28 +164,25 @@ export class ActivitybarPart extends Part implements IActivityBarService {
overflowActionSize: ActivitybarPart.ACTION_HEIGHT overflowActionSize: ActivitybarPart.ACTION_HEIGHT
})); }));
this.onDidRegisterViewContainers(this.getViewContainers());
this.registerListeners(); this.registerListeners();
this.onDidRegisterViewlets(viewletService.getViewlets());
} }
private registerListeners(): void { private registerListeners(): void {
// Viewlet registration // View Container Changes
this._register(this.viewletService.onDidViewletRegister(viewlet => this.onDidRegisterViewlets([viewlet]))); this._register(this.viewDescriptorService.onDidChangeViewContainers(({ added, removed }) => this.onDidChangeViewContainers(added, removed)));
this._register(this.viewletService.onDidViewletDeregister(({ id }) => this.onDidDeregisterViewlet(id))); this._register(this.viewDescriptorService.onDidChangeContainerLocation(({ viewContainer, from, to }) => this.onDidChangeViewContainerLocation(viewContainer, from, to)));
// Activate viewlet action on opening of a viewlet // View Container Visibility Changes
this._register(this.viewletService.onDidViewletOpen(viewlet => this.onDidViewletOpen(viewlet))); this._register(Event.filter(this.viewsService.onDidChangeViewContainerVisibility, e => e.location === this.location)(({ id, visible }) => this.onDidChangeViewContainerVisibility(id, visible)));
// Deactivate viewlet action on close
this._register(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId())));
// Extension registration // Extension registration
let disposables = this._register(new DisposableStore()); let disposables = this._register(new DisposableStore());
this._register(this.extensionService.onDidRegisterExtensions(() => { this._register(this.extensionService.onDidRegisterExtensions(() => {
disposables.clear(); disposables.clear();
this.onDidRegisterExtensions(); this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedViewlets(), this, disposables); this.compositeBar.onDidChange(() => this.saveCachedViewContainers(), this, disposables);
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables); this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
})); }));
@@ -200,39 +198,57 @@ export class ActivitybarPart extends Part implements IActivityBarService {
})); }));
} }
private onDidChangeViewContainers(added: ReadonlyArray<{ container: ViewContainer, location: ViewContainerLocation }>, removed: ReadonlyArray<{ container: ViewContainer, location: ViewContainerLocation }>) {
removed.filter(({ location }) => location === ViewContainerLocation.Sidebar).forEach(({ container }) => this.onDidDeregisterViewContainer(container));
this.onDidRegisterViewContainers(added.filter(({ location }) => location === ViewContainerLocation.Sidebar).map(({ container }) => container));
}
private onDidChangeViewContainerLocation(container: ViewContainer, from: ViewContainerLocation, to: ViewContainerLocation) {
if (from === this.location) {
this.onDidDeregisterViewContainer(container);
}
if (to === this.location) {
this.onDidRegisterViewContainers([container]);
}
}
private onDidChangeViewContainerVisibility(id: string, visible: boolean) {
if (visible) {
// Activate view container action on opening of a view container
this.onDidViewContainerVisible(id);
} else {
// Deactivate view container action on close
this.compositeBar.deactivateComposite(id);
}
}
private onDidRegisterExtensions(): void { private onDidRegisterExtensions(): void {
this.removeNotExistingComposites(); this.removeNotExistingComposites();
this.saveCachedViewlets(); this.saveCachedViewContainers();
} }
private onDidViewletOpen(viewlet: IViewlet): void { private onDidViewContainerVisible(id: string): void {
const viewContainer = this.getViewContainer(id);
if (viewContainer) {
// Update the composite bar by adding // Update the composite bar by adding
const foundViewlet = this.viewletService.getViewlet(viewlet.getId()); this.compositeBar.addComposite(viewContainer);
if (foundViewlet) { this.compositeBar.activateComposite(viewContainer.id);
this.compositeBar.addComposite(foundViewlet);
}
this.compositeBar.activateComposite(viewlet.getId()); if (viewContainer.hideIfEmpty) {
const viewletDescriptor = this.viewletService.getViewlet(viewlet.getId());
if (viewletDescriptor) {
const viewContainer = this.getViewContainer(viewletDescriptor.id);
if (viewContainer?.hideIfEmpty) {
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
if (viewContainerModel.activeViewDescriptors.length === 0) { if (viewContainerModel.activeViewDescriptors.length === 0) {
this.hideComposite(viewletDescriptor.id); // Update the composite bar by hiding this.hideComposite(viewContainer.id); // Update the composite bar by hiding
} }
} }
} }
} }
showActivity(viewletOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable { showActivity(viewContainerOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable {
if (this.viewletService.getViewlet(viewletOrActionId)) { if (this.getViewContainer(viewContainerOrActionId)) {
return this.compositeBar.showActivity(viewletOrActionId, badge, clazz, priority); return this.compositeBar.showActivity(viewContainerOrActionId, badge, clazz, priority);
} }
if (viewletOrActionId === GLOBAL_ACTIVITY_ID) { if (viewContainerOrActionId === GLOBAL_ACTIVITY_ID) {
return this.showGlobalActivity(badge, clazz, priority); return this.showGlobalActivity(badge, clazz, priority);
} }
@@ -342,7 +358,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.installMenubar(); this.installMenubar();
} }
// Viewlets action bar // View Containers action bar
this.compositeBar.create(this.content); this.compositeBar.create(this.content);
// Global action bar // Global action bar
@@ -444,19 +460,20 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.globalActivityActionBar.push(this.globalActivityAction); this.globalActivityActionBar.push(this.globalActivityAction);
} }
private getCompositeActions(compositeId: string): { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } { private getCompositeActions(compositeId: string): { activityAction: ViewContainerActivityAction, pinnedAction: ToggleCompositePinnedAction } {
let compositeActions = this.compositeActions.get(compositeId); let compositeActions = this.compositeActions.get(compositeId);
if (!compositeActions) { if (!compositeActions) {
const viewlet = this.viewletService.getViewlet(compositeId); const viewContainer = this.getViewContainer(compositeId);
if (viewlet) { if (viewContainer) {
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
compositeActions = { compositeActions = {
activityAction: this.instantiationService.createInstance(ViewletActivityAction, viewlet), activityAction: this.instantiationService.createInstance(ViewContainerActivityAction, this.toActivity(viewContainer, viewContainerModel)),
pinnedAction: new ToggleCompositePinnedAction(viewlet, this.compositeBar) pinnedAction: new ToggleCompositePinnedAction(viewContainer, this.compositeBar)
}; };
} else { } else {
const cachedComposite = this.cachedViewlets.filter(c => c.id === compositeId)[0]; const cachedComposite = this.cachedViewContainers.filter(c => c.id === compositeId)[0];
compositeActions = { compositeActions = {
activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite?.icon), activityAction: this.instantiationService.createInstance(PlaceHolderViewContainerActivityAction, ActivitybarPart.toActivity(compositeId, compositeId, cachedComposite?.icon, undefined)),
pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar) pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar)
}; };
} }
@@ -467,28 +484,27 @@ export class ActivitybarPart extends Part implements IActivityBarService {
return compositeActions; return compositeActions;
} }
private onDidRegisterViewlets(viewlets: ViewletDescriptor[]): void { private onDidRegisterViewContainers(viewContainers: ReadonlyArray<ViewContainer>): void {
for (const viewlet of viewlets) { for (const viewContainer of viewContainers) {
const cachedViewlet = this.cachedViewlets.filter(({ id }) => id === viewlet.id)[0]; const cachedViewContainer = this.cachedViewContainers.filter(({ id }) => id === viewContainer.id)[0];
const activeViewlet = this.viewletService.getActiveViewlet(); const visibleViewContainer = this.viewsService.getVisibleViewContainer(this.location);
const isActive = activeViewlet?.getId() === viewlet.id; const isActive = visibleViewContainer?.id === viewContainer.id;
if (isActive || !this.shouldBeHidden(viewlet.id, cachedViewlet)) { if (isActive || !this.shouldBeHidden(viewContainer.id, cachedViewContainer)) {
this.compositeBar.addComposite(viewlet); this.compositeBar.addComposite(viewContainer);
// Pin it by default if it is new // Pin it by default if it is new
if (!cachedViewlet) { if (!cachedViewContainer) {
this.compositeBar.pin(viewlet.id); this.compositeBar.pin(viewContainer.id);
} }
if (isActive) { if (isActive) {
this.compositeBar.activateComposite(viewlet.id); this.compositeBar.activateComposite(viewContainer.id);
} }
} }
} }
for (const viewlet of viewlets) { for (const viewContainer of viewContainers) {
const viewContainer = this.getViewContainer(viewlet.id)!;
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
this.updateActivity(viewContainer, viewContainerModel); this.updateActivity(viewContainer, viewContainerModel);
this.onDidChangeActiveViews(viewContainer, viewContainerModel); this.onDidChangeActiveViews(viewContainer, viewContainerModel);
@@ -497,38 +513,53 @@ export class ActivitybarPart extends Part implements IActivityBarService {
disposables.add(viewContainerModel.onDidChangeContainerInfo(() => this.updateActivity(viewContainer, viewContainerModel))); disposables.add(viewContainerModel.onDidChangeContainerInfo(() => this.updateActivity(viewContainer, viewContainerModel)));
disposables.add(viewContainerModel.onDidChangeActiveViewDescriptors(() => this.onDidChangeActiveViews(viewContainer, viewContainerModel))); disposables.add(viewContainerModel.onDidChangeActiveViewDescriptors(() => this.onDidChangeActiveViews(viewContainer, viewContainerModel)));
this.viewletDisposables.set(viewlet.id, disposables); this.viewContainerDisposables.set(viewContainer.id, disposables);
} }
} }
private onDidDeregisterViewlet(viewletId: string): void { private onDidDeregisterViewContainer(viewContainer: ViewContainer): void {
const disposable = this.viewletDisposables.get(viewletId); const disposable = this.viewContainerDisposables.get(viewContainer.id);
if (disposable) { if (disposable) {
disposable.dispose(); disposable.dispose();
} }
this.viewletDisposables.delete(viewletId); this.viewContainerDisposables.delete(viewContainer.id);
this.hideComposite(viewletId); this.hideComposite(viewContainer.id);
} }
private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void { private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void {
const activity: IActivity = this.toActivity(viewContainer, viewContainerModel);
const activity: IActivity = {
id: viewContainer.id,
name: viewContainerModel.title,
iconUrl: URI.isUri(viewContainerModel.icon) ? viewContainerModel.icon : undefined,
cssClass: isString(viewContainerModel.icon) ? viewContainerModel.icon : undefined,
keybindingId: viewContainer.focusCommand?.id || viewContainer.id
};
const { activityAction, pinnedAction } = this.getCompositeActions(viewContainer.id); const { activityAction, pinnedAction } = this.getCompositeActions(viewContainer.id);
activityAction.setActivity(activity); activityAction.updateActivity(activity);
if (pinnedAction instanceof PlaceHolderToggleCompositePinnedAction) { if (pinnedAction instanceof PlaceHolderToggleCompositePinnedAction) {
pinnedAction.setActivity(activity); pinnedAction.setActivity(activity);
} }
this.saveCachedViewlets(); this.saveCachedViewContainers();
}
private toActivity({ id, focusCommand }: ViewContainer, { icon, title: name }: IViewContainerModel): IActivity {
return ActivitybarPart.toActivity(id, name, icon, focusCommand?.id || id);
}
private static toActivity(id: string, name: string, icon: URI | string | undefined, keybindingId: string | undefined): IActivity {
let cssClass: string | undefined = undefined;
let iconUrl: URI | undefined = undefined;
if (URI.isUri(icon)) {
iconUrl = icon;
cssClass = `activity-${id.replace(/\./g, '-')}`;
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${cssClass}`;
createCSSRule(iconClass, `
mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
mask-size: 24px;
-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
-webkit-mask-size: 24px;
`);
} else if (isString(icon)) {
cssClass = icon;
}
return { id, name, cssClass, iconUrl, keybindingId };
} }
private onDidChangeActiveViews(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void { private onDidChangeActiveViews(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void {
@@ -539,21 +570,21 @@ export class ActivitybarPart extends Part implements IActivityBarService {
} }
} }
private shouldBeHidden(viewletId: string, cachedViewlet?: ICachedViewlet): boolean { private shouldBeHidden(viewContainerId: string, cachedViewContainer?: ICachedViewContainer): boolean {
const viewContainer = this.getViewContainer(viewletId); const viewContainer = this.getViewContainer(viewContainerId);
if (!viewContainer || !viewContainer.hideIfEmpty) { if (!viewContainer || !viewContainer.hideIfEmpty) {
return false; return false;
} }
return cachedViewlet?.views && cachedViewlet.views.length return cachedViewContainer?.views && cachedViewContainer.views.length
? cachedViewlet.views.every(({ when }) => !!when && !this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(when))) ? cachedViewContainer.views.every(({ when }) => !!when && !this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(when)))
: viewletId === TEST_VIEW_CONTAINER_ID /* Hide Test viewlet for the first time or it had no views registered before */; : viewContainerId === TEST_VIEW_CONTAINER_ID /* Hide Test view container for the first time or it had no views registered before */;
} }
private removeNotExistingComposites(): void { private removeNotExistingComposites(): void {
const viewlets = this.viewletService.getViewlets(); const viewContainers = this.getViewContainers();
for (const { id } of this.cachedViewlets) { for (const { id } of this.cachedViewContainers) {
if (viewlets.every(viewlet => viewlet.id !== id)) { if (viewContainers.every(viewContainer => viewContainer.id !== id)) {
this.hideComposite(id); this.hideComposite(id);
} }
} }
@@ -570,15 +601,20 @@ export class ActivitybarPart extends Part implements IActivityBarService {
} }
} }
getPinnedViewletIds(): string[] { getPinnedViewContainerIds(): string[] {
const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id); const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id);
return this.getViewContainers()
return this.viewletService.getViewlets()
.filter(v => this.compositeBar.isPinned(v.id)) .filter(v => this.compositeBar.isPinned(v.id))
.sort((v1, v2) => pinnedCompositeIds.indexOf(v1.id) - pinnedCompositeIds.indexOf(v2.id)) .sort((v1, v2) => pinnedCompositeIds.indexOf(v1.id) - pinnedCompositeIds.indexOf(v2.id))
.map(v => v.id); .map(v => v.id);
} }
getVisibleViewContainerIds(): string[] {
return this.compositeBar.getVisibleComposites()
.filter(v => this.viewsService.getVisibleViewContainer(this.location)?.id === v.id || this.compositeBar.isPinned(v.id))
.map(v => v.id);
}
layout(width: number, height: number): void { layout(width: number, height: number): void {
if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) {
return; return;
@@ -601,27 +637,32 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.compositeBar.layout(new Dimension(width, availableHeight)); this.compositeBar.layout(new Dimension(width, availableHeight));
} }
private getViewContainer(viewletId: string): ViewContainer | undefined { private getViewContainer(id: string): ViewContainer | undefined {
return this.viewDescriptorService.getViewContainerById(viewletId) || undefined; const viewContainer = this.viewDescriptorService.getViewContainerById(id);
return viewContainer && this.viewDescriptorService.getViewContainerLocation(viewContainer) === this.location ? viewContainer : undefined;
}
private getViewContainers(): ReadonlyArray<ViewContainer> {
return this.viewDescriptorService.getViewContainersByLocation(this.location);
} }
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void { private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
if (e.key === ActivitybarPart.PINNED_VIEWLETS && e.scope === StorageScope.GLOBAL if (e.key === ActivitybarPart.PINNED_VIEW_CONTAINERS && e.scope === StorageScope.GLOBAL
&& this.pinnedViewletsValue !== this.getStoredPinnedViewletsValue() /* This checks if current window changed the value or not */) { && this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) {
this._pinnedViewletsValue = undefined; this._pinnedViewContainersValue = undefined;
const newCompositeItems: ICompositeBarItem[] = []; const newCompositeItems: ICompositeBarItem[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems(); const compositeItems = this.compositeBar.getCompositeBarItems();
const cachedViewlets = this.getCachedViewlets(); const cachedViewContainers = this.getCachedViewContainers();
for (const cachedViewlet of cachedViewlets) { for (const cachedViewContainer of cachedViewContainers) {
// Add and update existing items // Add and update existing items
const existingItem = compositeItems.filter(({ id }) => id === cachedViewlet.id)[0]; const existingItem = compositeItems.filter(({ id }) => id === cachedViewContainer.id)[0];
if (existingItem) { if (existingItem) {
newCompositeItems.push({ newCompositeItems.push({
id: existingItem.id, id: existingItem.id,
name: existingItem.name, name: existingItem.name,
order: existingItem.order, order: existingItem.order,
pinned: cachedViewlet.pinned, pinned: cachedViewContainer.pinned,
visible: existingItem.visible visible: existingItem.visible
}); });
} }
@@ -638,8 +679,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
} }
} }
private saveCachedViewlets(): void { private saveCachedViewContainers(): void {
const state: ICachedViewlet[] = []; const state: ICachedViewContainer[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems(); const compositeItems = this.compositeBar.getCompositeBarItems();
for (const compositeItem of compositeItems) { for (const compositeItem of compositeItems) {
@@ -665,32 +706,32 @@ export class ActivitybarPart extends Part implements IActivityBarService {
} }
} }
this.storeCachedViewletsState(state); this.storeCachedViewContainersState(state);
} }
private getCachedViewlets(): ICachedViewlet[] { private getCachedViewContainers(): ICachedViewContainer[] {
const cachedViewlets: ICachedViewlet[] = this.getPinnedViewlets(); const cachedViewContainers: ICachedViewContainer[] = this.getPinnedViewContainers();
for (const placeholderViewlet of this.getPlaceholderViewlets()) { for (const placeholderViewContainer of this.getPlaceholderViewContainers()) {
const cachedViewlet = cachedViewlets.filter(cached => cached.id === placeholderViewlet.id)[0]; const cachedViewContainer = cachedViewContainers.filter(cached => cached.id === placeholderViewContainer.id)[0];
if (cachedViewlet) { if (cachedViewContainer) {
cachedViewlet.name = placeholderViewlet.name; cachedViewContainer.name = placeholderViewContainer.name;
cachedViewlet.icon = placeholderViewlet.iconCSS ? placeholderViewlet.iconCSS : cachedViewContainer.icon = placeholderViewContainer.iconCSS ? placeholderViewContainer.iconCSS :
placeholderViewlet.iconUrl ? URI.revive(placeholderViewlet.iconUrl) : undefined; placeholderViewContainer.iconUrl ? URI.revive(placeholderViewContainer.iconUrl) : undefined;
cachedViewlet.views = placeholderViewlet.views; cachedViewContainer.views = placeholderViewContainer.views;
} }
} }
return cachedViewlets; return cachedViewContainers;
} }
private storeCachedViewletsState(cachedViewlets: ICachedViewlet[]): void { private storeCachedViewContainersState(cachedViewContainers: ICachedViewContainer[]): void {
this.setPinnedViewlets(cachedViewlets.map(({ id, pinned, visible, order }) => (<IPinnedViewlet>{ this.setPinnedViewContainers(cachedViewContainers.map(({ id, pinned, visible, order }) => (<IPinnedViewContainer>{
id, id,
pinned, pinned,
visible, visible,
order order
}))); })));
this.setPlaceholderViewlets(cachedViewlets.map(({ id, icon, name, views }) => (<IPlaceholderViewlet>{ this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views }) => (<IPlaceholderViewContainer>{
id, id,
iconUrl: URI.isUri(icon) ? icon : undefined, iconUrl: URI.isUri(icon) ? icon : undefined,
iconCSS: isString(icon) ? icon : undefined, iconCSS: isString(icon) ? icon : undefined,
@@ -699,80 +740,80 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}))); })));
} }
private getPinnedViewlets(): IPinnedViewlet[] { private getPinnedViewContainers(): IPinnedViewContainer[] {
return JSON.parse(this.pinnedViewletsValue); return JSON.parse(this.pinnedViewContainersValue);
} }
private setPinnedViewlets(pinnedViewlets: IPinnedViewlet[]): void { private setPinnedViewContainers(pinnedViewContainers: IPinnedViewContainer[]): void {
this.pinnedViewletsValue = JSON.stringify(pinnedViewlets); this.pinnedViewContainersValue = JSON.stringify(pinnedViewContainers);
} }
private _pinnedViewletsValue: string | undefined; private _pinnedViewContainersValue: string | undefined;
private get pinnedViewletsValue(): string { private get pinnedViewContainersValue(): string {
if (!this._pinnedViewletsValue) { if (!this._pinnedViewContainersValue) {
this._pinnedViewletsValue = this.getStoredPinnedViewletsValue(); this._pinnedViewContainersValue = this.getStoredPinnedViewContainersValue();
} }
return this._pinnedViewletsValue; return this._pinnedViewContainersValue;
} }
private set pinnedViewletsValue(pinnedViewletsValue: string) { private set pinnedViewContainersValue(pinnedViewContainersValue: string) {
if (this.pinnedViewletsValue !== pinnedViewletsValue) { if (this.pinnedViewContainersValue !== pinnedViewContainersValue) {
this._pinnedViewletsValue = pinnedViewletsValue; this._pinnedViewContainersValue = pinnedViewContainersValue;
this.setStoredPinnedViewletsValue(pinnedViewletsValue); this.setStoredPinnedViewContainersValue(pinnedViewContainersValue);
} }
} }
private getStoredPinnedViewletsValue(): string { private getStoredPinnedViewContainersValue(): string {
return this.storageService.get(ActivitybarPart.PINNED_VIEWLETS, StorageScope.GLOBAL, '[]'); return this.storageService.get(ActivitybarPart.PINNED_VIEW_CONTAINERS, StorageScope.GLOBAL, '[]');
} }
private setStoredPinnedViewletsValue(value: string): void { private setStoredPinnedViewContainersValue(value: string): void {
this.storageService.store(ActivitybarPart.PINNED_VIEWLETS, value, StorageScope.GLOBAL); this.storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
} }
private getPlaceholderViewlets(): IPlaceholderViewlet[] { private getPlaceholderViewContainers(): IPlaceholderViewContainer[] {
return JSON.parse(this.placeholderViewletsValue); return JSON.parse(this.placeholderViewContainersValue);
} }
private setPlaceholderViewlets(placeholderViewlets: IPlaceholderViewlet[]): void { private setPlaceholderViewContainers(placeholderViewContainers: IPlaceholderViewContainer[]): void {
this.placeholderViewletsValue = JSON.stringify(placeholderViewlets); this.placeholderViewContainersValue = JSON.stringify(placeholderViewContainers);
} }
private _placeholderViewletsValue: string | undefined; private _placeholderViewContainersValue: string | undefined;
private get placeholderViewletsValue(): string { private get placeholderViewContainersValue(): string {
if (!this._placeholderViewletsValue) { if (!this._placeholderViewContainersValue) {
this._placeholderViewletsValue = this.getStoredPlaceholderViewletsValue(); this._placeholderViewContainersValue = this.getStoredPlaceholderViewContainersValue();
} }
return this._placeholderViewletsValue; return this._placeholderViewContainersValue;
} }
private set placeholderViewletsValue(placeholderViewletsValue: string) { private set placeholderViewContainersValue(placeholderViewContainesValue: string) {
if (this.placeholderViewletsValue !== placeholderViewletsValue) { if (this.placeholderViewContainersValue !== placeholderViewContainesValue) {
this._placeholderViewletsValue = placeholderViewletsValue; this._placeholderViewContainersValue = placeholderViewContainesValue;
this.setStoredPlaceholderViewletsValue(placeholderViewletsValue); this.setStoredPlaceholderViewContainersValue(placeholderViewContainesValue);
} }
} }
private getStoredPlaceholderViewletsValue(): string { private getStoredPlaceholderViewContainersValue(): string {
return this.storageService.get(ActivitybarPart.PLACEHOLDER_VIEWLETS, StorageScope.GLOBAL, '[]'); return this.storageService.get(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, StorageScope.GLOBAL, '[]');
} }
private setStoredPlaceholderViewletsValue(value: string): void { private setStoredPlaceholderViewContainersValue(value: string): void {
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEWLETS, value, StorageScope.GLOBAL); this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
} }
private migrateFromOldCachedViewletsValue(): void { private migrateFromOldCachedViewContainersValue(): void {
const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL); const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
if (value !== undefined) { if (value !== undefined) {
const storedStates: Array<string | ICachedViewlet> = JSON.parse(value); const storedStates: Array<string | ICachedViewContainer> = JSON.parse(value);
const cachedViewlets = storedStates.map(c => { const cachedViewContainers = storedStates.map(c => {
const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, icon: undefined, views: undefined } : c; const serialized: ICachedViewContainer = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, icon: undefined, views: undefined } : c;
serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible; serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible;
return serialized; return serialized;
}); });
this.storeCachedViewletsState(cachedViewlets); this.storeCachedViewContainersState(cachedViewContainers);
this.storageService.remove('workbench.activity.pinnedViewlets', StorageScope.GLOBAL); this.storageService.remove('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
} }
} }
+17 -5
View File
@@ -37,11 +37,11 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
constructor( constructor(
private viewDescriptorService: IViewDescriptorService, private viewDescriptorService: IViewDescriptorService,
private targetContainerLocation: ViewContainerLocation, private targetContainerLocation: ViewContainerLocation,
private openComposite: (id: string, focus?: boolean) => Promise<IPaneComposite | undefined>, private openComposite: (id: string, focus?: boolean) => Promise<IPaneComposite | null>,
private moveComposite: (from: string, to: string, before?: Before2D) => void, private moveComposite: (from: string, to: string, before?: Before2D) => void,
) { } ) { }
drop(data: CompositeDragAndDropData, targetCompositeId: string, originalEvent: DragEvent, before?: Before2D): void { drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent, before?: Before2D): void {
const dragData = data.getData(); const dragData = data.getData();
if (dragData.type === 'composite') { if (dragData.type === 'composite') {
@@ -50,8 +50,10 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
// ... on the same composite bar // ... on the same composite bar
if (currentLocation === this.targetContainerLocation) { if (currentLocation === this.targetContainerLocation) {
if (targetCompositeId) {
this.moveComposite(dragData.id, targetCompositeId, before); this.moveComposite(dragData.id, targetCompositeId, before);
} }
}
// ... on a different composite bar // ... on a different composite bar
else { else {
const viewsToMove = this.viewDescriptorService.getViewContainerModel(currentContainer)!.allViewDescriptors; const viewsToMove = this.viewDescriptorService.getViewContainerModel(currentContainer)!.allViewDescriptors;
@@ -60,7 +62,10 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
} }
this.viewDescriptorService.moveViewContainerToLocation(currentContainer, this.targetContainerLocation); this.viewDescriptorService.moveViewContainerToLocation(currentContainer, this.targetContainerLocation);
if (targetCompositeId) {
this.moveComposite(currentContainer.id, targetCompositeId, before); this.moveComposite(currentContainer.id, targetCompositeId, before);
}
this.openComposite(currentContainer.id, true); this.openComposite(currentContainer.id, true);
} }
@@ -74,7 +79,9 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
const newContainer = this.viewDescriptorService.getViewContainerByViewId(viewToMove.id)!; const newContainer = this.viewDescriptorService.getViewContainerByViewId(viewToMove.id)!;
if (targetCompositeId) {
this.moveComposite(newContainer.id, targetCompositeId, before); this.moveComposite(newContainer.id, targetCompositeId, before);
}
this.openComposite(newContainer.id, true).then(composite => { this.openComposite(newContainer.id, true).then(composite => {
if (composite) { if (composite) {
@@ -140,7 +147,7 @@ export interface ICompositeBarOptions {
getOnCompositeClickAction: (compositeId: string) => Action; getOnCompositeClickAction: (compositeId: string) => Action;
getContextMenuActions: () => Action[]; getContextMenuActions: () => Action[];
getContextMenuActionsForComposite: (compositeId: string) => Action[]; getContextMenuActionsForComposite: (compositeId: string) => Action[];
openComposite: (compositeId: string) => Promise<IComposite | undefined>; openComposite: (compositeId: string) => Promise<IComposite | null>;
getDefaultCompositeId: () => string; getDefaultCompositeId: () => string;
hidePart: () => void; hidePart: () => void;
} }
@@ -188,6 +195,10 @@ export class CompositeBar extends Widget implements ICompositeBar {
return this.model.pinnedItems; return this.model.pinnedItems;
} }
getVisibleComposites(): ICompositeBarItem[] {
return this.model.visibleItems;
}
create(parent: HTMLElement): HTMLElement { create(parent: HTMLElement): HTMLElement {
const actionBarDiv = parent.appendChild($('.composite-bar')); const actionBarDiv = parent.appendChild($('.composite-bar'));
this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, { this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, {
@@ -264,7 +275,8 @@ export class CompositeBar extends Widget implements ICompositeBar {
// Add to the model // Add to the model
if (this.model.add(id, name, order)) { if (this.model.add(id, name, order)) {
this.computeSizes([this.model.findItem(id)]); this.computeSizes([this.model.findItem(id)]);
this.updateCompositeSwitcher(); // Set timeout helps prevent flicker
setTimeout(() => this.updateCompositeSwitcher(), 0);
} }
} }
@@ -526,7 +538,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
}); });
// Add overflow action as needed // Add overflow action as needed
if ((visibleCompositesChange && overflows) || compositeSwitcherBar.length() === 0) { if ((visibleCompositesChange && overflows)) {
this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => { this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => {
if (this.compositeOverflowActionViewItem) { if (this.compositeOverflowActionViewItem) {
this.compositeOverflowActionViewItem.showMenu(); this.compositeOverflowActionViewItem.showMenu();
@@ -91,7 +91,7 @@ class Item extends BreadcrumbsItem {
fileKind: this.element.kind, fileKind: this.element.kind,
fileDecorations: { colors: this.options.showDecorationColors, badges: false }, fileDecorations: { colors: this.options.showDecorationColors, badges: false },
}); });
dom.addClass(container, FileKind[this.element.kind].toLowerCase()); container.classList.add(FileKind[this.element.kind].toLowerCase());
this._disposables.add(label); this._disposables.add(label);
} else if (this.element instanceof OutlineModel) { } else if (this.element instanceof OutlineModel) {
@@ -113,7 +113,7 @@ class Item extends BreadcrumbsItem {
let icon = document.createElement('div'); let icon = document.createElement('div');
icon.className = SymbolKinds.toCssClassName(this.element.symbol.kind); icon.className = SymbolKinds.toCssClassName(this.element.symbol.kind);
container.appendChild(icon); container.appendChild(icon);
dom.addClass(container, 'shows-symbol-icon'); container.classList.add('shows-symbol-icon');
} }
let label = new IconLabel(container); let label = new IconLabel(container);
let title = this.element.symbol.name.replace(/\r|\n|\r\n/g, '\u23CE'); let title = this.element.symbol.name.replace(/\r|\n|\r\n/g, '\u23CE');
@@ -183,7 +183,7 @@ export class BreadcrumbsControl {
@IBreadcrumbsService breadcrumbsService: IBreadcrumbsService, @IBreadcrumbsService breadcrumbsService: IBreadcrumbsService,
) { ) {
this.domNode = document.createElement('div'); this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'breadcrumbs-control'); this.domNode.classList.add('breadcrumbs-control');
dom.append(container, this.domNode); dom.append(container, this.domNode);
this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService); this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService);
@@ -221,13 +221,13 @@ export class BreadcrumbsControl {
} }
isHidden(): boolean { isHidden(): boolean {
return dom.hasClass(this.domNode, 'hidden'); return this.domNode.classList.contains('hidden');
} }
hide(): void { hide(): void {
this._breadcrumbsDisposables.clear(); this._breadcrumbsDisposables.clear();
this._ckBreadcrumbsVisible.set(false); this._ckBreadcrumbsVisible.set(false);
dom.toggleClass(this.domNode, 'hidden', true); this.domNode.classList.toggle('hidden', true);
} }
update(): boolean { update(): boolean {
@@ -251,7 +251,7 @@ export class BreadcrumbsControl {
} }
} }
dom.toggleClass(this.domNode, 'hidden', false); this.domNode.classList.toggle('hidden', false);
this._ckBreadcrumbsVisible.set(true); this._ckBreadcrumbsVisible.set(true);
this._ckBreadcrumbsPossible.set(true); this._ckBreadcrumbsPossible.set(true);
@@ -263,8 +263,8 @@ export class BreadcrumbsControl {
this._textResourceConfigurationService, this._textResourceConfigurationService,
this._workspaceService this._workspaceService
); );
dom.toggleClass(this.domNode, 'relative-path', model.isRelative()); this.domNode.classList.toggle('relative-path', model.isRelative());
dom.toggleClass(this.domNode, 'backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\'); this.domNode.classList.toggle('backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\');
const updateBreadcrumbs = () => { const updateBreadcrumbs = () => {
const showIcons = this._cfShowIcons.getValue(); const showIcons = this._cfShowIcons.getValue();
@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { compareFileNames } from 'vs/base/common/comparers'; import { compareFileNames } from 'vs/base/common/comparers';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
@@ -375,11 +374,11 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
_createTree(container: HTMLElement) { _createTree(container: HTMLElement) {
// tree icon theme specials // tree icon theme specials
dom.addClass(this._treeContainer, 'file-icon-themable-tree'); this._treeContainer.classList.add('file-icon-themable-tree');
dom.addClass(this._treeContainer, 'show-file-icons'); this._treeContainer.classList.add('show-file-icons');
const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => { const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => {
dom.toggleClass(this._treeContainer, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons); this._treeContainer.classList.toggle('align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons);
dom.toggleClass(this._treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true); this._treeContainer.classList.toggle('hide-arrows', fileIconTheme.hidesExplorerArrows === true);
}; };
this._disposables.add(this._themeService.onDidFileIconThemeChange(onFileIconThemeChange)); this._disposables.add(this._themeService.onDidFileIconThemeChange(onFileIconThemeChange));
onFileIconThemeChange(this._themeService.getFileIconTheme()); onFileIconThemeChange(this._themeService.getFileIconTheme());
@@ -123,7 +123,7 @@ export class EditorControl extends Disposable {
private doInstantiateEditorPane(descriptor: IEditorDescriptor): BaseEditor { private doInstantiateEditorPane(descriptor: IEditorDescriptor): BaseEditor {
// Return early if already instantiated // Return early if already instantiated
const existingEditorPane = this.editorPanes.filter(editorPane => descriptor.describes(editorPane))[0]; const existingEditorPane = this.editorPanes.find(editorPane => descriptor.describes(editorPane));
if (existingEditorPane) { if (existingEditorPane) {
return existingEditorPane; return existingEditorPane;
} }
@@ -16,7 +16,6 @@ import { GroupDirection, MergeGroupMode } from 'vs/workbench/services/editor/com
import { toDisposable } from 'vs/base/common/lifecycle'; import { toDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { RunOnceScheduler } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
import { find } from 'vs/base/common/arrays';
import { DataTransfers } from 'vs/base/browser/dnd'; import { DataTransfers } from 'vs/base/browser/dnd';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
@@ -600,7 +599,7 @@ export class EditorDropTarget extends Themable {
private findTargetGroupView(child: HTMLElement): IEditorGroupView | undefined { private findTargetGroupView(child: HTMLElement): IEditorGroupView | undefined {
const groups = this.accessor.groups; const groups = this.accessor.groups;
return find(groups, groupView => isAncestor(child, groupView.element) || this.delegate.groupContainsPredicate?.(groupView)); return groups.find(groupView => isAncestor(child, groupView.element) || this.delegate.groupContainsPredicate?.(groupView));
} }
private updateContainer(isDraggedOver: boolean): void { private updateContainer(isDraggedOver: boolean): void {
@@ -1604,7 +1604,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Forward to controls // Forward to controls
this.layoutTitleAreaControl(width); this.layoutTitleAreaControl(width);
this.editorControl.layout(new Dimension(this.dimension.width, this.dimension.height - this.titleAreaControl.getPreferredHeight())); this.editorControl.layout(new Dimension(this.dimension.width, Math.max(0, this.dimension.height - this.titleAreaControl.getPreferredHeight())));
} }
private layoutTitleAreaControl(width: number): void { private layoutTitleAreaControl(width: number): void {

Some files were not shown because too many files have changed in this diff Show More