diff --git a/.github/commands.json b/.github/commands.json index bd319fe1148..b2be2ca22b5 100644 --- a/.github/commands.json +++ b/.github/commands.json @@ -440,5 +440,13 @@ "name": "*workspace-trust-docs", "action": "close", "comment": "This issue appears to be the result of the new workspace trust feature shipped in June 2021. This security-focused feature has major impact on the functionality of VS Code. Due to the volume of issues, we ask that you take some time to review our [comprehensive documentation](https://aka.ms/vscode-workspace-trust) on the feature. If your issue is still not resolved, please let us know." + }, + { + "type": "label", + "name": "~verification-steps-needed", + "action": "updateLabels", + "addLabel": "verification-steps-needed", + "removeLabel": "~verification-steps-needed", + "comment": "Friendly ping! Looks like this issue requires some further steps to be verified. Please provide us with the steps necessary to verify this issue." } ] diff --git a/build/azure-pipelines/common/computeBuiltInDepsCacheKey.js b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.js new file mode 100644 index 00000000000..abc90f6ed2c --- /dev/null +++ b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.js @@ -0,0 +1,15 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = require("fs"); +const path = require("path"); +const crypto = require("crypto"); +const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../product.json'), 'utf8')); +const shasum = crypto.createHash('sha1'); +for (const ext of productjson.builtInExtensions) { + shasum.update(`${ext.name}@${ext.version}`); +} +process.stdout.write(shasum.digest('hex')); diff --git a/build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts new file mode 100644 index 00000000000..f0554361607 --- /dev/null +++ b/build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as crypto from 'crypto'; + +const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../product.json'), 'utf8')); +const shasum = crypto.createHash('sha1'); + +for (const ext of productjson.builtInExtensions) { + shasum.update(`${ext.name}@${ext.version}`); +} + +process.stdout.write(shasum.digest('hex')); diff --git a/build/azure-pipelines/darwin/product-build-darwin-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-sign.yml index c7baec86b5f..72fd19ab27d 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-sign.yml @@ -38,6 +38,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -49,7 +50,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/darwin/product-build-darwin-universal.yml b/build/azure-pipelines/darwin/product-build-darwin-universal.yml index 80c16f5acff..ebc7104d6ce 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-universal.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-universal.yml @@ -38,6 +38,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js x64 $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -49,7 +50,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index f33df4096d6..e82a7cfa2e6 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -72,6 +72,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -83,7 +84,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index 0faef3e7571..c60f16d0804 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -58,6 +58,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js "alpine" $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -69,7 +70,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 2031e1d9f38..a2deeb9f5a9 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -91,6 +91,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -111,7 +112,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/product-build-pr-cache.yml b/build/azure-pipelines/product-build-pr-cache.yml index 17dd3b71919..042325394d3 100644 --- a/build/azure-pipelines/product-build-pr-cache.yml +++ b/build/azure-pipelines/product-build-pr-cache.yml @@ -10,6 +10,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -21,7 +22,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 5b67ef001f5..2b5bdc5b53a 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -46,6 +46,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags # using `genericNodeModules` instead of `nodeModules` here to avoid sharing the cache with builds running inside containers @@ -59,7 +60,7 @@ steps: # Cache built-in extensions to avoid GH rate limits. - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index 01130cf089a..61e409d4859 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -49,6 +49,7 @@ steps: - script: | mkdir -p .build node build/azure-pipelines/common/computeNodeModulesCacheKey.js "web" $ENABLE_TERRAPIN > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -60,7 +61,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index a12612737c0..bb19e4c0068 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -80,6 +80,7 @@ steps: "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch "$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin node build/azure-pipelines/common/computeNodeModulesCacheKey.js > .build/yarnlockhash + node build/azure-pipelines/common/computeBuiltInDepsCacheKey.js > .build/builtindepshash displayName: Prepare yarn cache flags - task: Cache@2 @@ -91,7 +92,7 @@ steps: - task: Cache@2 inputs: - key: '"$(Agent.OS)" | product.json' + key: '"builtInDeps" | .build/builtindepshash' path: .build/builtInExtensions displayName: Restore built-in extensions diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 009bbe4b014..a13c5686b7d 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -351,12 +351,20 @@ function scanBuiltinExtensions(extensionsRoot, exclude = []) { const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + let browserNlsMetadataPath; + if (packageJSON.browser) { + const browserEntrypointFolderPath = path.join(extensionFolder, path.dirname(packageJSON.browser)); + if (fs.existsSync(path.join(extensionsRoot, browserEntrypointFolderPath, 'nls.metadata.json'))) { + browserNlsMetadataPath = path.join(browserEntrypointFolderPath, 'nls.metadata.json'); + } + } const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; scannedExtensions.push({ extensionPath: extensionFolder, packageJSON, packageNLS, + browserNlsMetadataPath, readmePath: readme ? path.join(extensionFolder, readme) : undefined, changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, }); diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index d14ddca2f8a..fdd7d9c3c0d 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -412,6 +412,7 @@ export interface IScannedBuiltinExtension { extensionPath: string; packageJSON: any; packageNLS?: any; + browserNlsMetadataPath?: string; readmePath?: string; changelogPath?: string; } @@ -436,6 +437,13 @@ export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + let browserNlsMetadataPath: string | undefined; + if (packageJSON.browser) { + const browserEntrypointFolderPath = path.join(extensionFolder, path.dirname(packageJSON.browser)); + if (fs.existsSync(path.join(extensionsRoot, browserEntrypointFolderPath, 'nls.metadata.json'))) { + browserNlsMetadataPath = path.join(browserEntrypointFolderPath, 'nls.metadata.json'); + } + } const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; @@ -443,6 +451,7 @@ export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] extensionPath: extensionFolder, packageJSON, packageNLS, + browserNlsMetadataPath, readmePath: readme ? path.join(extensionFolder, readme) : undefined, changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, }); diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index fdd714a55c2..a124a0432e6 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "jsonc-parser": "^2.2.1", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "capabilities": { "virtualWorkspaces": true, diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index f7ac959fc09..e8272098f1e 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -12,7 +12,7 @@ jsonc-parser@^2.2.1: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc" integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index ccf0518633f..99f9bc18352 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -995,7 +995,7 @@ }, "dependencies": { "vscode-languageclient": "^8.0.2-next.4", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 9b7854145e5..95d981a70c7 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -73,10 +73,10 @@ vscode-languageserver-types@3.17.2-next.2: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/debug-auto-launch/package.json b/extensions/debug-auto-launch/package.json index 82c9054c456..80ea639b5f3 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -33,7 +33,7 @@ ] }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-auto-launch/yarn.lock b/extensions/debug-auto-launch/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/debug-auto-launch/yarn.lock +++ b/extensions/debug-auto-launch/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index 29cee88c0c5..3b570124452 100644 --- a/extensions/debug-server-ready/package.json +++ b/extensions/debug-server-ready/package.json @@ -150,7 +150,7 @@ ] }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/debug-server-ready/yarn.lock +++ b/extensions/debug-server-ready/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index abceee2bc7d..add192a06c0 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -29,7 +29,7 @@ "jsonc-parser": "^2.2.1", "markdown-it": "^12.3.2", "parse5": "^3.0.2", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "contributes": { "jsonValidation": [ diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index ac87f5e2686..3aa5397f837 100644 --- a/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -67,7 +67,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/git-base/package.json b/extensions/git-base/package.json index 07e95e3a1ae..1c7daa3b4b9 100644 --- a/extensions/git-base/package.json +++ b/extensions/git-base/package.json @@ -100,7 +100,7 @@ ] }, "dependencies": { - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/git-base/yarn.lock b/extensions/git-base/yarn.lock index 8fb6777123c..0cd0d3ce8f2 100644 --- a/extensions/git-base/yarn.lock +++ b/extensions/git-base/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.21.tgz#474d7589a30afcf5291f59bd49cca9ad171ffde4" integrity sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/git/package.json b/extensions/git/package.json index 0b2195c6034..f7af2dfdbee 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -2719,7 +2719,7 @@ "file-type": "^7.2.0", "jschardet": "3.0.0", "picomatch": "2.3.1", - "vscode-nls": "^4.0.0", + "vscode-nls": "^5.1.0", "vscode-uri": "^2.0.0", "which": "^1.3.0" }, diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index a5d6607b1d8..6a09be018fe 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -120,10 +120,10 @@ picomatch@2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-uri@^2.0.0: version "2.0.0" diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index a130c199928..d9ccdc42d4c 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -62,7 +62,7 @@ "node-fetch": "2.6.7", "uuid": "8.1.0", "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "vscode-tas-client": "^0.1.47" }, "devDependencies": { diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index 118ed320b0f..6ebb79992dc 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -143,10 +143,10 @@ uuid@8.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-tas-client@^0.1.47: version "0.1.47" diff --git a/extensions/github/package.json b/extensions/github/package.json index a5de87a74b7..218e8f949ed 100644 --- a/extensions/github/package.json +++ b/extensions/github/package.json @@ -132,7 +132,7 @@ "dependencies": { "@octokit/rest": "^18.0.1", "tunnel": "^0.0.6", - "vscode-nls": "^4.1.2" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/github/yarn.lock b/extensions/github/yarn.lock index 9933736b08e..5465f9ba25a 100644 --- a/extensions/github/yarn.lock +++ b/extensions/github/yarn.lock @@ -153,10 +153,10 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -vscode-nls@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" - integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== webidl-conversions@^3.0.0: version "3.0.1" diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index 8dd9eced530..245fd717f8c 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:grunt" }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/grunt/yarn.lock b/extensions/grunt/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/grunt/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index 8352957083e..062dc4a788f 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:gulp" }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/gulp/yarn.lock b/extensions/gulp/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/gulp/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 7e4120eeb05..64e623de887 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -260,7 +260,7 @@ "dependencies": { "@vscode/extension-telemetry": "0.5.1", "vscode-languageclient": "^8.0.2-next.4", - "vscode-nls": "^5.0.1", + "vscode-nls": "^5.1.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index fc9b3634c9a..405e17bbbe2 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -13,7 +13,7 @@ "vscode-html-languageservice": "^5.0.1", "vscode-languageserver": "^8.0.2-next.4", "vscode-languageserver-textdocument": "^1.0.4", - "vscode-nls": "^5.0.1", + "vscode-nls": "^5.1.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 7f6ae130b3f..1c95f5f4056 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -72,6 +72,11 @@ vscode-nls@^5.0.1: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== + vscode-uri@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index c7c2faeae0f..2d2f101eba6 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -78,10 +78,10 @@ vscode-languageserver-types@3.17.2-next.2: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== -vscode-nls@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index 1ad296a9905..3beaf419b47 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -80,7 +80,7 @@ }, "dependencies": { "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "repository": { "type": "git", diff --git a/extensions/image-preview/yarn.lock b/extensions/image-preview/yarn.lock index da44f29eaa4..61a6bb946db 100644 --- a/extensions/image-preview/yarn.lock +++ b/extensions/image-preview/yarn.lock @@ -46,7 +46,7 @@ "@microsoft/1ds-core-js" "^3.2.3" "@microsoft/1ds-post-js" "^3.2.3" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/ipynb/package.json b/extensions/ipynb/package.json index b7250aee1f4..ef01fa6baa6 100644 --- a/extensions/ipynb/package.json +++ b/extensions/ipynb/package.json @@ -9,7 +9,8 @@ "vscode": "^1.57.0" }, "enabledApiProposals": [ - "notebookWorkspaceEdit" + "notebookWorkspaceEdit", + "documentPaste" ], "activationEvents": [ "*" @@ -27,6 +28,21 @@ } }, "contributes": { + "configuration":[ + { + "properties": { + "ipynb.experimental.pasteImages.enabled":{ + "type": "boolean", + "scope": "resource", + "markdownDescription": "%ipynb.experimental.pasteImages.enabled%", + "default": false, + "tags": [ + "experimental" + ] + } + } + } + ], "commands": [ { "command": "ipynb.newUntitledIpynb", diff --git a/extensions/ipynb/package.nls.json b/extensions/ipynb/package.nls.json index 6f2f7e47c0c..fc7592584de 100644 --- a/extensions/ipynb/package.nls.json +++ b/extensions/ipynb/package.nls.json @@ -1,4 +1,5 @@ { "displayName": ".ipynb support", - "description": "Provides basic support for opening and reading Jupyter's .ipynb notebook files" + "description": "Provides basic support for opening and reading Jupyter's .ipynb notebook files", + "ipynb.experimental.pasteImages.enabled":"Enable/Disable pasting images into markdown cells within ipynb files. Requires enabling `#ipynb.experimental.pasteImages.enabled#`." } diff --git a/extensions/ipynb/src/cellAttachmentRenderer.ts b/extensions/ipynb/src/cellAttachmentRenderer.ts index 4f3626d5a18..722f6182708 100644 --- a/extensions/ipynb/src/cellAttachmentRenderer.ts +++ b/extensions/ipynb/src/cellAttachmentRenderer.ts @@ -22,7 +22,7 @@ export async function activate(ctx: RendererContext) { md.renderer.rules.image = (tokens: MarkdownItToken[], idx: number, options, env, self) => { const token = tokens[idx]; const src = token.attrGet('src'); - const attachments: Record> = env.outputItem.metadata().custom?.attachments; + const attachments: Record> = env.outputItem.metadata.custom?.attachments; if (attachments && src) { const imageAttachment = attachments[src.replace('attachment:', '')]; if (imageAttachment) { diff --git a/extensions/ipynb/src/ipynbMain.ts b/extensions/ipynb/src/ipynbMain.ts index 33bb1456af8..003c4c8f266 100644 --- a/extensions/ipynb/src/ipynbMain.ts +++ b/extensions/ipynb/src/ipynbMain.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import { ensureAllNewCellsHaveCellIds } from './cellIdService'; import { NotebookSerializer } from './notebookSerializer'; +import * as NotebookImagePaste from './notebookImagePaste'; // From {nbformat.INotebookMetadata} in @jupyterlab/coreutils type NotebookMetadata = { @@ -77,12 +78,15 @@ export function activate(context: vscode.ExtensionContext) { await vscode.window.showNotebookDocument(document); })); + context.subscriptions.push(NotebookImagePaste.imagePasteSetup()); + // Update new file contribution vscode.extensions.onDidChange(() => { vscode.commands.executeCommand('setContext', 'jupyterEnabled', vscode.extensions.getExtension('ms-toolsai.jupyter')); }); vscode.commands.executeCommand('setContext', 'jupyterEnabled', vscode.extensions.getExtension('ms-toolsai.jupyter')); + return { exportNotebook: (notebook: vscode.NotebookData): string => { return exportNotebook(notebook, serializer); diff --git a/extensions/ipynb/src/notebookImagePaste.ts b/extensions/ipynb/src/notebookImagePaste.ts new file mode 100644 index 00000000000..64137f82300 --- /dev/null +++ b/extensions/ipynb/src/notebookImagePaste.ts @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +class CopyPasteEditProvider implements vscode.DocumentPasteEditProvider { + + async provideDocumentPasteEdits( + _document: vscode.TextDocument, + _ranges: readonly vscode.Range[], + dataTransfer: vscode.DataTransfer, + _token: vscode.CancellationToken + ): Promise { + + const enabled = vscode.workspace.getConfiguration('ipynb', _document).get('experimental.pasteImages.enabled', false); + if (!enabled) { + return undefined; + } + + // get b64 data from paste + // TODO: dataTransfer.get() limits to one image pasted + const dataItem = dataTransfer.get('image/png'); + if (!dataItem) { + return undefined; + } + const fileDataAsUint8 = await dataItem.asFile()?.data(); + if (!fileDataAsUint8) { + return undefined; + } + + // get filename data from paste + let pasteFilename = dataItem.asFile()?.name; + if (!pasteFilename) { + return undefined; + } + const separatorIndex = pasteFilename?.lastIndexOf('.'); + const filename = pasteFilename?.slice(0, separatorIndex); + const filetype = pasteFilename?.slice(separatorIndex); + if (!filename || !filetype) { + return undefined; + } + + // get notebook cell data + let notebookUri; + let currentCell; + for (const notebook of vscode.workspace.notebookDocuments) { + if (notebook.uri.path === _document.uri.path) { + for (const cell of notebook.getCells()) { + if (cell.document === _document) { + currentCell = cell; + notebookUri = notebook.uri; + break; + } + } + } + } + if (!currentCell || !notebookUri) { + return undefined; + } + + // create updated metadata for cell (prep for WorkspaceEdit) + const b64string = encodeBase64(fileDataAsUint8); + const startingAttachments = currentCell.metadata?.custom?.attachments; + if (!startingAttachments) { + currentCell.metadata.custom['attachments'] = { [pasteFilename]: { 'image/png': b64string } }; + } else { + for (let appendValue = 2; pasteFilename in startingAttachments; appendValue++) { + const objEntries = Object.entries(startingAttachments[pasteFilename]); + if (objEntries.length) { // check that mime:b64 are present + const [, attachmentb64] = objEntries[0]; + if (attachmentb64 !== b64string) { // append a "-#" here. same name, diff data. this matches jupyter behavior + pasteFilename = filename.concat(`-${appendValue}`) + filetype; + } + } + } + currentCell.metadata.custom.attachments[pasteFilename] = { 'image/png': b64string }; + } + + const metadataNotebookEdit = vscode.NotebookEdit.updateCellMetadata(currentCell.index, currentCell.metadata); + const workspaceEdit = new vscode.WorkspaceEdit(); + if (metadataNotebookEdit) { + workspaceEdit.set(notebookUri, [metadataNotebookEdit]); + } + + // create a snippet for paste + const pasteSnippet = new vscode.SnippetString(); + pasteSnippet.appendText('!['); + pasteSnippet.appendPlaceholder(`${pasteFilename}`); + pasteSnippet.appendText(`](attachment:${pasteFilename})`); + + return { insertText: pasteSnippet, additionalEdit: workspaceEdit }; + } +} + +export function imagePasteSetup() { + const selector: vscode.DocumentSelector = { notebookType: 'jupyter-notebook', language: 'markdown' }; // this is correct provider + return vscode.languages.registerDocumentPasteEditProvider(selector, new CopyPasteEditProvider(), { + pasteMimeTypes: ['image/png'], + }); +} + +/** + * Taken from https://github.com/microsoft/vscode/blob/743b016722db90df977feecde0a4b3b4f58c2a4c/src/vs/base/common/buffer.ts#L350-L387 + */ +function encodeBase64(buffer: Uint8Array, padded = true, urlSafe = false) { + const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + const base64UrlSafeAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; + + const dictionary = urlSafe ? base64UrlSafeAlphabet : base64Alphabet; + let output = ''; + + const remainder = buffer.byteLength % 3; + + let i = 0; + for (; i < buffer.byteLength - remainder; i += 3) { + const a = buffer[i + 0]; + const b = buffer[i + 1]; + const c = buffer[i + 2]; + + output += dictionary[a >>> 2]; + output += dictionary[(a << 4 | b >>> 4) & 0b111111]; + output += dictionary[(b << 2 | c >>> 6) & 0b111111]; + output += dictionary[c & 0b111111]; + } + + if (remainder === 1) { + const a = buffer[i + 0]; + output += dictionary[a >>> 2]; + output += dictionary[(a << 4) & 0b111111]; + if (padded) { output += '=='; } + } else if (remainder === 2) { + const a = buffer[i + 0]; + const b = buffer[i + 1]; + output += dictionary[a >>> 2]; + output += dictionary[(a << 4 | b >>> 4) & 0b111111]; + output += dictionary[(b << 2) & 0b111111]; + if (padded) { output += '='; } + } + + return output; +} diff --git a/extensions/ipynb/tsconfig.json b/extensions/ipynb/tsconfig.json index a8006017458..50d718f424e 100644 --- a/extensions/ipynb/tsconfig.json +++ b/extensions/ipynb/tsconfig.json @@ -9,6 +9,7 @@ "include": [ "src/**/*", "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.notebookWorkspaceEdit.d.ts" + "../../src/vscode-dts/vscode.proposed.notebookWorkspaceEdit.d.ts", + "../../src/vscode-dts/vscode.proposed.documentPaste.d.ts" ] } diff --git a/extensions/jake/package.json b/extensions/jake/package.json index 0e5ebc4ea8b..5ffa78e3981 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -17,7 +17,7 @@ "watch": "gulp watch-extension:jake" }, "dependencies": { - "vscode-nls": "^4.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/jake/yarn.lock b/extensions/jake/yarn.lock index 22c406bc73f..90475ddc7e0 100644 --- a/extensions/jake/yarn.lock +++ b/extensions/jake/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 8f3345c2a6e..81a51598b1f 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -156,7 +156,7 @@ "@vscode/extension-telemetry": "0.6.2", "request-light": "^0.5.8", "vscode-languageclient": "^8.0.2-next.5", - "vscode-nls": "^5.0.1" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index 61f19346fde..e7574fd2c50 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -122,10 +122,10 @@ vscode-languageserver-types@3.17.2-next.2: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== -vscode-nls@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== yallist@^4.0.0: version "4.0.0" diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index 70dcfd6984b..05ebb019dec 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -259,11 +259,10 @@ export const activate: ActivationFunction = (ctx) => { code { font-size: 1em; + font-family: var(--vscode-editor-font-family); } pre code { - font-family: var(--vscode-editor-font-family); - line-height: 1.357em; white-space: pre-wrap; } diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index ffa9336499b..6f3c76d708f 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -568,7 +568,7 @@ "picomatch": "^2.3.1", "vscode-languageclient": "^8.0.1", "vscode-languageserver-textdocument": "^1.0.4", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 3150da7a642..956d9a937f1 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -263,16 +263,16 @@ vscode-markdown-languageservice@^0.0.0-alpha.10: vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== - vscode-nls@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== + vscode-uri@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index efc984ed5b9..d10085c4fc6 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -158,7 +158,7 @@ } }, "dependencies": { - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index 699f1238a9b..90475ddc7e0 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index f8b8a6931d0..b40c7bb17b5 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -61,7 +61,7 @@ "stream": "0.0.2", "uuid": "^8.2.0", "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "repository": { "type": "git", diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index 45e0f9a89f0..f32f33bdc96 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -184,6 +184,9 @@ export class AzureActiveDirectoryService { if (!modifiedScopes.includes('profile')) { modifiedScopes.push('profile'); } + if (!modifiedScopes.includes('offline_access')) { + modifiedScopes.push('offline_access'); + } modifiedScopes = modifiedScopes.sort(); let modifiedScopesStr = modifiedScopes.join(' '); diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index 9328b1d4b1a..6706f6a4aae 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -198,10 +198,10 @@ uuid@^8.2.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.2.0.tgz#cb10dd6b118e2dada7d0cd9730ba7417c93d920e" integrity sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== webidl-conversions@^3.0.0: version "3.0.1" diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 0a0cd05411f..9cc9ac5dedb 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -22,7 +22,7 @@ "jsonc-parser": "^2.2.1", "minimatch": "^3.0.4", "request-light": "^0.5.7", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "which": "^2.0.2", "which-pm": "^2.0.0" }, diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index bba9ffdbf39..3479f1c58b6 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -192,10 +192,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== which-pm@^2.0.0: version "2.0.0" diff --git a/extensions/php-language-features/package.json b/extensions/php-language-features/package.json index 8c0d484535b..8782b3d83b4 100644 --- a/extensions/php-language-features/package.json +++ b/extensions/php-language-features/package.json @@ -74,7 +74,7 @@ "watch": "npx gulp watch-extension:php-language-features" }, "dependencies": { - "vscode-nls": "^4.0.0", + "vscode-nls": "^5.1.0", "which": "^2.0.2" }, "devDependencies": { diff --git a/extensions/php-language-features/yarn.lock b/extensions/php-language-features/yarn.lock index 8dec3aadc63..62c8b33e55d 100644 --- a/extensions/php-language-features/yarn.lock +++ b/extensions/php-language-features/yarn.lock @@ -17,10 +17,10 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== which@^2.0.2: version "2.0.2" diff --git a/extensions/references-view/package.json b/extensions/references-view/package.json index f5c0a910f1e..4176cda3d1a 100644 --- a/extensions/references-view/package.json +++ b/extensions/references-view/package.json @@ -407,7 +407,7 @@ "watch": "npx gulp watch-extension:references-view" }, "dependencies": { - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/references-view/yarn.lock b/extensions/references-view/yarn.lock index 0f041514ffc..76eaba8dd6f 100644 --- a/extensions/references-view/yarn.lock +++ b/extensions/references-view/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.33.tgz#566713b1b626f781c5c58fe3531307283e00720c" integrity sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA== -vscode-nls@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" - integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/shared.webpack.config.js b/extensions/shared.webpack.config.js index 37eed9c9b85..59689e5b16b 100644 --- a/extensions/shared.webpack.config.js +++ b/extensions/shared.webpack.config.js @@ -70,6 +70,10 @@ function withNodeDefaults(/**@type WebpackConfig*/extConfig) { return merge(defaultConfig, extConfig); } +/** + * + * @param {string} context + */ function nodePlugins(context) { // Need to find the top-most `package.json` file const folderName = path.relative(__dirname, context).split(/[\\\/]/)[0]; @@ -109,6 +113,13 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi test: /\.ts$/, exclude: /node_modules/, use: [{ + // vscode-nls-dev loader: + // * rewrite nls-calls + loader: 'vscode-nls-dev/lib/webpack-loader', + options: { + base: path.join(extConfig.context, 'src') + } + }, { // configure TypeScript loader: // * enable sources maps for end-to-end source maps loader: 'ts-loader', @@ -123,6 +134,7 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi }, externals: { 'vscode': 'commonjs vscode', // ignored because it doesn't exist, + 'vscode-nls-web-data': 'commonjs vscode-nls-web-data', // ignored because this is injected by the webworker extension host 'applicationinsights-native-metrics': 'commonjs applicationinsights-native-metrics', // ignored because we don't ship native module '@opentelemetry/tracing': 'commonjs @opentelemetry/tracing' // ignored because we don't ship this module }, @@ -138,30 +150,39 @@ function withBrowserDefaults(/**@type WebpackConfig*/extConfig, /** @type Additi }, // yes, really source maps devtool: 'source-map', - plugins: browserPlugins + plugins: browserPlugins(extConfig.context) }; return merge(defaultConfig, extConfig); } -const browserPlugins = [ - new optimize.LimitChunkCountPlugin({ - maxChunks: 1 - }), - new CopyWebpackPlugin({ - patterns: [ - { from: 'src', to: '.', globOptions: { ignore: ['**/test/**', '**/*.ts'] }, noErrorOnMissing: true } - ] - }), - new DefinePlugin({ - 'process.platform': JSON.stringify('web'), - 'process.env': JSON.stringify({}), - 'process.env.BROWSER_ENV': JSON.stringify('true') - }) -]; - - - +/** + * + * @param {string} context + */ +function browserPlugins(context) { + // Need to find the top-most `package.json` file + const folderName = path.relative(__dirname, context).split(/[\\\/]/)[0]; + const pkgPath = path.join(__dirname, folderName, 'package.json'); + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + const id = `${pkg.publisher}.${pkg.name}`; + return [ + new optimize.LimitChunkCountPlugin({ + maxChunks: 1 + }), + new CopyWebpackPlugin({ + patterns: [ + { from: 'src', to: '.', globOptions: { ignore: ['**/test/**', '**/*.ts'] }, noErrorOnMissing: true } + ] + }), + new DefinePlugin({ + 'process.platform': JSON.stringify('web'), + 'process.env': JSON.stringify({}), + 'process.env.BROWSER_ENV': JSON.stringify('true') + }), + new NLSBundlePlugin(id) + ]; +} module.exports = withNodeDefaults; module.exports.node = withNodeDefaults; diff --git a/extensions/simple-browser/package.json b/extensions/simple-browser/package.json index 08344e234f1..fe3f4de2a5f 100644 --- a/extensions/simple-browser/package.json +++ b/extensions/simple-browser/package.json @@ -68,7 +68,7 @@ }, "dependencies": { "@vscode/extension-telemetry": "0.6.2", - "vscode-nls": "^5.0.0" + "vscode-nls": "^5.1.0" }, "devDependencies": { "@types/vscode-webview": "^1.57.0", diff --git a/extensions/simple-browser/yarn.lock b/extensions/simple-browser/yarn.lock index 5faf627618c..32215e9059b 100644 --- a/extensions/simple-browser/yarn.lock +++ b/extensions/simple-browser/yarn.lock @@ -56,7 +56,7 @@ vscode-codicons@^0.0.14: resolved "https://registry.yarnpkg.com/vscode-codicons/-/vscode-codicons-0.0.14.tgz#e0d05418e2e195564ff6f6a2199d70415911c18f" integrity sha512-6CEH5KT9ct5WMw7n5dlX7rB8ya4CUI2FSq1Wk36XaW+c5RglFtAanUV0T+gvZVVFhl/WxfjTvFHq06Hz9c1SLA== -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== diff --git a/extensions/typescript-language-features/extension-browser.webpack.config.js b/extensions/typescript-language-features/extension-browser.webpack.config.js index e7dbbe999fa..6dbedab0a05 100644 --- a/extensions/typescript-language-features/extension-browser.webpack.config.js +++ b/extensions/typescript-language-features/extension-browser.webpack.config.js @@ -37,7 +37,7 @@ module.exports = withBrowserDefaults({ extension: './src/extension.browser.ts', }, plugins: [ - ...browserPlugins, // add plugins, don't replace inherited + ...browserPlugins(__dirname), // add plugins, don't replace inherited // @ts-ignore new CopyPlugin({ diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index be5a8bacb28..15a96456934 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -37,7 +37,7 @@ "@vscode/extension-telemetry": "0.6.2", "jsonc-parser": "^2.2.1", "semver": "5.5.1", - "vscode-nls": "^5.0.0", + "vscode-nls": "^5.1.0", "vscode-tas-client": "^0.1.47", "vscode-uri": "^3.0.3" }, diff --git a/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock index c400b672129..81f56c011a9 100644 --- a/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -85,10 +85,10 @@ tas-client@0.1.45: dependencies: axios "^0.26.1" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.1.0.tgz#443b301a7465d88c81c0f4e1914f9857f0dce1e4" + integrity sha512-37Ha44QrLFwR2IfSSYdOArzUvOyoWbOYTwQC+wS0NfqKjhW7s0WQ1lMy5oJXgSZy9sAiZS5ifELhbpXodeMR8w== vscode-tas-client@^0.1.47: version "0.1.47" diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts index d41129e04f4..923ee4cfc73 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.kernel.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import 'mocha'; import { TextDecoder } from 'util'; import * as vscode from 'vscode'; -import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, disposeAll, revertAllDirty, saveAllEditors } from '../utils'; +import { asPromise, assertNoRpc, closeAllEditors, createRandomFile, DeferredPromise, disposeAll, revertAllDirty, saveAllEditors } from '../utils'; async function createRandomNotebookFile() { return createRandomFile('', undefined, '.vsctestnb'); @@ -181,7 +181,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = { const editor = vscode.window.activeNotebookEditor!; const cell = editor.notebook.cellAt(0); - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => { await vscode.commands.executeCommand('notebook.execute'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked @@ -196,7 +196,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = { const secondResource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); - await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async event => { await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, notebook.uri); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked @@ -204,35 +204,33 @@ const apiTestContentProvider: vscode.NotebookContentProvider = { }); }); - // #126371 - test('cell execute command takes arguments', async () => { + test('cell execute command takes arguments 2', async () => { const notebook = await openRandomNotebookDocument(); await vscode.window.showNotebookDocument(notebook); let firstCellExecuted = false; let secondCellExecuted = false; - let resolve: () => void; - const p = new Promise(r => resolve = r); - const listener = vscode.workspace.onDidChangeNotebookDocument(e => { + + const def = new DeferredPromise(); + testDisposables.push(vscode.workspace.onDidChangeNotebookDocument(e => { e.cellChanges.forEach(change => { - if (change.cell.index === 0) { + if (change.cell.index === 0 && change.executionSummary) { firstCellExecuted = true; } - if (change.cell.index === 1) { + if (change.cell.index === 1 && change.executionSummary) { secondCellExecuted = true; } }); if (firstCellExecuted && secondCellExecuted) { - resolve(); + def.complete(); } - }); + })); vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] }); - await p; - listener.dispose(); + await def.p; await saveAllFilesAndCloseAll(); }); @@ -301,27 +299,30 @@ const apiTestContentProvider: vscode.NotebookContentProvider = { const cell = editor.notebook.cellAt(0); let eventCount = 0; - let resolve: () => void; - const p = new Promise(r => resolve = r); - const listener = vscode.notebooks.onDidChangeNotebookCellExecutionState(e => { - if (eventCount === 0) { - assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending'); - } else if (eventCount === 1) { - assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing'); - assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0])); - } else if (eventCount === 2) { - assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Idle, 'should be set to Idle'); - assert.strictEqual(cell.outputs.length, 1, 'should have an output'); - resolve(); - } + const def = new DeferredPromise(); + testDisposables.push(vscode.notebooks.onDidChangeNotebookCellExecutionState(e => { + try { + assert.strictEqual(e.cell.document.uri.toString(), cell.document.uri.toString(), 'event should be fired for the executing cell'); - eventCount++; - }); + if (eventCount === 0) { + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending'); + } else if (eventCount === 1) { + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing'); + assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0])); + } else if (e.state === vscode.NotebookCellExecutionState.Idle) { + assert.strictEqual(cell.outputs.length, 1, 'should have an output'); + def.complete(); + } + + eventCount++; + } catch (err) { + def.error(err); + } + })); vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }] }); - await p; - listener.dispose(); + await def.p; }); test('Output changes are applied once the promise resolves', async function () { diff --git a/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts index cd2a653bee8..7c506694289 100644 --- a/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -184,3 +184,61 @@ export async function poll( trial++; } } + +export type ValueCallback = (value: T | Promise) => void; + +/** + * Creates a promise whose resolution or rejection can be controlled imperatively. + */ +export class DeferredPromise { + + private completeCallback!: ValueCallback; + private errorCallback!: (err: unknown) => void; + private rejected = false; + private resolved = false; + + public get isRejected() { + return this.rejected; + } + + public get isResolved() { + return this.resolved; + } + + public get isSettled() { + return this.rejected || this.resolved; + } + + public readonly p: Promise; + + constructor() { + this.p = new Promise((c, e) => { + this.completeCallback = c; + this.errorCallback = e; + }); + } + + public complete(value: T) { + return new Promise(resolve => { + this.completeCallback(value); + this.resolved = true; + resolve(); + }); + } + + public error(err: unknown) { + return new Promise(resolve => { + this.errorCallback(err); + this.rejected = true; + resolve(); + }); + } + + public cancel() { + new Promise(resolve => { + this.errorCallback(new Error('Canceled')); + this.rejected = true; + resolve(); + }); + } +} diff --git a/package.json b/package.json index c9a24421f9c..f8cfd0e725a 100644 --- a/package.json +++ b/package.json @@ -170,11 +170,11 @@ "husky": "^0.13.1", "innosetup": "6.0.5", "is": "^3.1.0", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.2.0", "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.1.5", "lazy.js": "^0.4.2", "merge-options": "^1.0.1", "mime": "^1.4.1", diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 3ddc0d543ba..1c69a349c09 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -101,22 +101,6 @@ export function addDisposableGenericMouseUpListener(node: EventTarget, handler: return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_UP : EventType.MOUSE_UP, handler, useCapture); } -export function createEventEmitter(target: HTMLElement, type: K, options?: boolean | AddEventListenerOptions): event.Emitter { - let domListener: IDisposable | undefined = undefined; - const handler = (e: HTMLElementEventMap[K]) => result.fire(e); - const onFirstListenerAdd = () => { - if (!domListener) { - domListener = addDisposableListener(target, type, handler, options); - } - }; - const onLastListenerRemove = () => { - domListener?.dispose(); - domListener = undefined; - }; - const result = new event.Emitter({ onFirstListenerAdd, onLastListenerRemove }); - return result; -} - interface IRequestAnimationFrame { (callback: (time: number) => void): number; } @@ -836,11 +820,12 @@ export interface EventLike { } export const EventHelper = { - stop: function (e: EventLike, cancelBubble?: boolean) { + stop: (e: T, cancelBubble?: boolean): T => { e.preventDefault(); if (cancelBubble) { e.stopPropagation(); } + return e; } }; diff --git a/src/vs/base/browser/event.ts b/src/vs/base/browser/event.ts index adef057e119..600a5f78248 100644 --- a/src/vs/base/browser/event.ts +++ b/src/vs/base/browser/event.ts @@ -45,18 +45,3 @@ export class DomEmitter implements IDisposable { this.emitter.dispose(); } } - -export interface CancellableEvent { - preventDefault(): void; - stopPropagation(): void; -} - -export function stopEvent(event: T): T { - event.preventDefault(); - event.stopPropagation(); - return event; -} - -export function stop(event: BaseEvent): BaseEvent { - return BaseEvent.map(event, stopEvent); -} diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 7b9a6cb481e..0e97d180ef1 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -218,7 +218,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { return; } const title = this.getTooltip() ?? ''; - this.element.setAttribute('aria-label', title); + this.updateAriaLabel(); if (!this.options.hoverDelegate) { this.element.title = title; } else { @@ -232,6 +232,13 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } } + protected updateAriaLabel(): void { + if (this.element) { + const title = this.getTooltip() ?? ''; + this.element.setAttribute('aria-label', title); + } + } + protected updateClass(): void { // implement in subclass } @@ -388,8 +395,7 @@ export class ActionViewItem extends BaseActionViewItem { } } - override updateTooltip(): void { - super.updateTooltip(); + override updateAriaLabel(): void { if (this.label) { const title = this.getTooltip() ?? ''; this.label.setAttribute('aria-label', title); diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 0cea984085d..8ed5f2d8602 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { IDragAndDropData } from 'vs/base/browser/dnd'; -import { createStyleSheet } from 'vs/base/browser/dom'; -import { DomEmitter, stopEvent } from 'vs/base/browser/event'; +import { createStyleSheet, EventHelper } from 'vs/base/browser/dom'; +import { DomEmitter } from 'vs/base/browser/event'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Gesture } from 'vs/base/browser/touch'; import { alert } from 'vs/base/browser/ui/aria/aria'; @@ -457,7 +457,7 @@ class TypeNavigationController implements IDisposable { .map(event => new StandardKeyboardEvent(event)) .filter(e => typing || this.keyboardNavigationEventFilter(e)) .filter(e => this.delegate.mightProducePrintableCharacter(e)) - .forEach(stopEvent) + .forEach(e => EventHelper.stop(e, true)) .map(event => event.browserEvent.key) .event; @@ -1288,7 +1288,7 @@ export class List implements ISpliceable, IThemable, IDisposable { const fromKeyDown = this.disposables.add(Event.chain(this.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event)) .map(e => new StandardKeyboardEvent(e)) .filter(e => didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10)) - .map(stopEvent) + .map(e => EventHelper.stop(e, true)) .filter(() => false) .event as Event; @@ -1296,7 +1296,7 @@ export class List implements ISpliceable, IThemable, IDisposable { .forEach(() => didJustPressContextMenuKey = false) .map(e => new StandardKeyboardEvent(e)) .filter(e => e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10)) - .map(stopEvent) + .map(e => EventHelper.stop(e, true)) .map(({ browserEvent }) => { const focus = this.getFocus(); const index = focus.length ? focus[0] : undefined; diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 393f3ea3fda..159c58a2797 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -52,7 +52,7 @@ export interface IView { readonly minimumSize: number; /** - * A minimum size for this view. + * A maximum size for this view. * * @remarks If none, set it to `Number.POSITIVE_INFINITY`. */ diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index e45c78ae5e3..562710d4c84 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -1389,7 +1389,7 @@ export class DeferredPromise { return this.rejected || this.resolved; } - public p: Promise; + public readonly p: Promise; constructor() { this.p = new Promise((c, e) => { diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index d959a938e93..2e6d00020c0 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -103,9 +103,9 @@ import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } fro import { PolicyChannelClient } from 'vs/platform/policy/common/policyIpc'; import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy'; import { UserDataProfilesNativeService } from 'vs/platform/userDataProfile/electron-sandbox/userDataProfile'; -import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender'; import { DefaultExtensionsProfileInitService } from 'vs/platform/extensionManagement/electron-sandbox/defaultExtensionsProfileInit'; import { SharedProcessRequestService } from 'vs/platform/request/electron-browser/sharedProcessRequestService'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; class SharedProcessMain extends Disposable { @@ -283,7 +283,7 @@ class SharedProcessMain extends Disposable { appenders.push(logAppender); const { installSourcePath } = environmentService; if (productService.aiConfig?.ariaKey) { - const collectorAppender = new OneDataSystemWebAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey); + const collectorAppender = new OneDataSystemAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey); this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data appenders.push(collectorAppender); } diff --git a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts index dc4a1692710..ed78a7d1963 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts @@ -73,6 +73,7 @@ export class IssueReporter extends Disposable { const targetExtension = configuration.data.extensionId ? configuration.data.enabledExtensions.find(extension => extension.id === configuration.data.extensionId) : undefined; this.issueReporterModel = new IssueReporterModel({ + ...configuration.data, issueType: configuration.data.issueType || IssueType.Bug, versionInfo: { vscodeVersion: `${configuration.product.nameShort} ${!!configuration.product.darwinUniversalAssetId ? `${configuration.product.version} (Universal)` : configuration.product.version} (${configuration.product.commit || 'Commit unknown'}, ${configuration.product.date || 'Date unknown'})`, @@ -80,7 +81,7 @@ export class IssueReporter extends Disposable { }, extensionsDisabled: !!configuration.disableExtensions, fileOnExtension: configuration.data.extensionId ? !targetExtension?.isBuiltin : undefined, - selectedExtension: targetExtension, + selectedExtension: targetExtension }); const issueReporterElement = this.getElementById('issue-reporter'); diff --git a/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css b/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css index 3baf48ce1af..080049662de 100644 --- a/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css +++ b/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css @@ -84,3 +84,15 @@ body { padding-left: 20px; white-space: nowrap; } + +.monaco-scrollable-element .scrollbar > .slider { + background: #64646457 !important; +} + +.monaco-scrollable-element .scrollbar > .slider:hover { + background: highlight !important; +} + +.monaco-scrollable-element .scrollbar > .slider.active { + background: highlight !important; +} diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts b/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts index 8e756e829d9..10d2243c333 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts @@ -257,6 +257,7 @@ class ProcessExplorer { await this.createProcessTree(processRoots); } else { this.tree.setInput({ processes: { processRoots } }); + this.tree.layout(window.innerHeight, window.innerWidth); } this.requestProcessList(0); @@ -342,6 +343,13 @@ class ProcessExplorer { this.showContextMenu(e.element, true); } }); + + container.style.height = `${window.innerHeight}px`; + + window.addEventListener('resize', () => { + container.style.height = `${window.innerHeight}px`; + this.tree?.layout(window.innerHeight, window.innerWidth); + }); } private isDebuggable(cmd: string): boolean { diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 3e7e9a3252e..1e785855191 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -5,6 +5,7 @@ import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; +import { DomEmitter } from 'vs/base/browser/event'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { RunOnceScheduler } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; @@ -672,19 +673,19 @@ class ClipboardEventUtils { export class TextAreaWrapper extends Disposable implements ICompleteTextAreaWrapper { - public readonly onKeyDown = this._register(dom.createEventEmitter(this._actual, 'keydown')).event; - public readonly onKeyPress = this._register(dom.createEventEmitter(this._actual, 'keypress')).event; - public readonly onKeyUp = this._register(dom.createEventEmitter(this._actual, 'keyup')).event; - public readonly onCompositionStart = this._register(dom.createEventEmitter(this._actual, 'compositionstart')).event; - public readonly onCompositionUpdate = this._register(dom.createEventEmitter(this._actual, 'compositionupdate')).event; - public readonly onCompositionEnd = this._register(dom.createEventEmitter(this._actual, 'compositionend')).event; - public readonly onBeforeInput = this._register(dom.createEventEmitter(this._actual, 'beforeinput')).event; - public readonly onInput = >this._register(dom.createEventEmitter(this._actual, 'input')).event; - public readonly onCut = this._register(dom.createEventEmitter(this._actual, 'cut')).event; - public readonly onCopy = this._register(dom.createEventEmitter(this._actual, 'copy')).event; - public readonly onPaste = this._register(dom.createEventEmitter(this._actual, 'paste')).event; - public readonly onFocus = this._register(dom.createEventEmitter(this._actual, 'focus')).event; - public readonly onBlur = this._register(dom.createEventEmitter(this._actual, 'blur')).event; + public readonly onKeyDown = this._register(new DomEmitter(this._actual, 'keydown')).event; + public readonly onKeyPress = this._register(new DomEmitter(this._actual, 'keypress')).event; + public readonly onKeyUp = this._register(new DomEmitter(this._actual, 'keyup')).event; + public readonly onCompositionStart = this._register(new DomEmitter(this._actual, 'compositionstart')).event; + public readonly onCompositionUpdate = this._register(new DomEmitter(this._actual, 'compositionupdate')).event; + public readonly onCompositionEnd = this._register(new DomEmitter(this._actual, 'compositionend')).event; + public readonly onBeforeInput = this._register(new DomEmitter(this._actual, 'beforeinput')).event; + public readonly onInput = >this._register(new DomEmitter(this._actual, 'input')).event; + public readonly onCut = this._register(new DomEmitter(this._actual, 'cut')).event; + public readonly onCopy = this._register(new DomEmitter(this._actual, 'copy')).event; + public readonly onPaste = this._register(new DomEmitter(this._actual, 'paste')).event; + public readonly onFocus = this._register(new DomEmitter(this._actual, 'focus')).event; + public readonly onBlur = this._register(new DomEmitter(this._actual, 'blur')).event; private _onSyntheticTap = this._register(new Emitter()); public readonly onSyntheticTap: Event = this._onSyntheticTap.event; diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index 69bd02b765b..8ae2e294982 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -323,6 +323,7 @@ export interface IExtension { readonly changelogUrl?: URI; readonly isValid: boolean; readonly validations: readonly [Severity, string][]; + readonly browserNlsBundleUris?: { [language: string]: URI }; } /** @@ -389,6 +390,7 @@ export interface IRelaxedExtensionDescription extends IRelaxedExtensionManifest isUserBuiltin: boolean; isUnderDevelopment: boolean; extensionLocation: URI; + browserNlsBundleUris?: { [language: string]: URI }; } export type IExtensionDescription = Readonly; diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index c5a327c71e7..9b6968f03aa 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -31,7 +31,7 @@ export interface IFileService { readonly onDidChangeFileSystemProviderRegistrations: Event; /** - * An event that is fired when a registered file system provider changes it's capabilities. + * An event that is fired when a registered file system provider changes its capabilities. */ readonly onDidChangeFileSystemProviderCapabilities: Event; @@ -80,7 +80,7 @@ export interface IFileService { hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean; /** - * List the schemes and capabilies for registered file system providers + * List the schemes and capabilities for registered file system providers */ listCapabilities(): Iterable<{ scheme: string; capabilities: FileSystemProviderCapabilities }>; @@ -982,7 +982,7 @@ interface IBaseFileStat { readonly ctime?: number; /** - * A unique identifier thet represents the + * A unique identifier that represents the * current state of the file or directory. * * The value may or may not be resolved as diff --git a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts index 45bad3159a1..bed836ec2fd 100644 --- a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts +++ b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts @@ -138,7 +138,7 @@ const terminalPlatformConfiguration: IConfigurationNode = { }, [TerminalSettingId.AutomationProfileLinux]: { restricted: true, - markdownDescription: localize('terminal.integrated.automationProfile.linux', "The terminal profile to use on Linux for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} is set.", '`#terminal.integrated.automationShell.linux#`'), + markdownDescription: localize('terminal.integrated.automationProfile.linux', "The terminal profile to use on Linux for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} (now deprecated) is set.", '`terminal.integrated.automationShell.linux`'), type: ['object', 'null'], default: null, 'anyOf': [ @@ -156,7 +156,7 @@ const terminalPlatformConfiguration: IConfigurationNode = { }, [TerminalSettingId.AutomationProfileMacOs]: { restricted: true, - markdownDescription: localize('terminal.integrated.automationProfile.osx', "The terminal profile to use on macOS for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} is set.", '`#terminal.integrated.automationShell.osx#`'), + markdownDescription: localize('terminal.integrated.automationProfile.osx', "The terminal profile to use on macOS for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} (now deprecated) is set.", '`terminal.integrated.automationShell.osx`'), type: ['object', 'null'], default: null, 'anyOf': [ @@ -174,7 +174,7 @@ const terminalPlatformConfiguration: IConfigurationNode = { }, [TerminalSettingId.AutomationProfileWindows]: { restricted: true, - markdownDescription: localize('terminal.integrated.automationProfile.windows', "The terminal profile to use for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} is set.", '`#terminal.integrated.automationShell.windows#`'), + markdownDescription: localize('terminal.integrated.automationProfile.windows', "The terminal profile to use for automation-related terminal usage like tasks and debug. This setting will currently be ignored if {0} (now deprecated) is set.", '`terminal.integrated.automationShell.windows`'), type: ['object', 'null'], default: null, 'anyOf': [ diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 615de9d6b5a..4c81a3d1f30 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -213,9 +213,9 @@ export class PtyService extends Disposable implements IPtyService { async attachToProcess(id: number): Promise { try { await this._throwIfNoPty(id).attach(); - this._logService.trace(`Persistent process reconnection "${id}"`); + this._logService.info(`Persistent process reconnection "${id}"`); } catch (e) { - this._logService.trace(`Persistent process reconnection "${id}" failed`, e.message); + this._logService.warn(`Persistent process reconnection "${id}" failed`, e.message); throw e; } } @@ -341,7 +341,7 @@ export class PtyService extends Disposable implements IPtyService { try { return this._revivedPtyIdMap.get(id)?.newId; } catch (e) { - this._logService.trace(`Couldn't find terminal ID ${id}`, e.message); + this._logService.warn(`Couldn't find terminal ID ${id}`, e.message); } return undefined; } @@ -384,7 +384,7 @@ export class PtyService extends Disposable implements IPtyService { relativeSize: t.relativeSize }; } catch (e) { - this._logService.trace(`Couldn't get layout info, a terminal was probably disconnected`, e.message); + this._logService.warn(`Couldn't get layout info, a terminal was probably disconnected`, e.message); // this will be filtered out and not reconnected return { terminal: null, @@ -582,12 +582,12 @@ export class PersistentTerminalProcess extends Disposable { async attach(): Promise { this._logService.trace('persistentTerminalProcess#attach', this._persistentProcessId); + // Something wrong happened if the disconnect runner is not canceled, this likely means + // multiple windows attempted to attach. + if (!await this._isOrphaned()) { + throw new Error(`Cannot attach to persistent process "${this._persistentProcessId}", it is already adopted`); + } if (!this._disconnectRunner1.isScheduled() && !this._disconnectRunner2.isScheduled()) { - // Something wrong happened if the disconnect runner is not canceled, this likely means - // multiple windows attempted to attach. - if (!await this._isOrphaned()) { - throw new Error(`Cannot attach to persistent process "${this._persistentProcessId}", it is already adopted`); - } this._logService.warn(`Persistent process "${this._persistentProcessId}": Process had no disconnect runners but was an orphan`); } this._disconnectRunner1.cancel(); diff --git a/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts index a1c2461be9d..e1d2428631b 100644 --- a/src/vs/platform/terminal/node/terminalEnvironment.ts +++ b/src/vs/platform/terminal/node/terminalEnvironment.ts @@ -223,8 +223,9 @@ export enum ShellIntegrationExecutable { } export const shellIntegrationArgs: Map = new Map(); -shellIntegrationArgs.set(ShellIntegrationExecutable.WindowsPwsh, ['-noexit', '-command', '. \"{0}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1\"{1}']); -shellIntegrationArgs.set(ShellIntegrationExecutable.WindowsPwshLogin, ['-l', '-noexit', '-command', '. \"{0}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1\"{1}']); +// The try catch swallows execution policy errors in the case of the archive distributable +shellIntegrationArgs.set(ShellIntegrationExecutable.WindowsPwsh, ['-noexit', '-command', 'try { . \"{0}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1\" } catch {}{1}']); +shellIntegrationArgs.set(ShellIntegrationExecutable.WindowsPwshLogin, ['-l', '-noexit', '-command', 'try { . \"{0}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1\" } catch {}{1}']); shellIntegrationArgs.set(ShellIntegrationExecutable.Pwsh, ['-noexit', '-command', '. "{0}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1"{1}']); shellIntegrationArgs.set(ShellIntegrationExecutable.PwshLogin, ['-l', '-noexit', '-command', '. "{0}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1"']); shellIntegrationArgs.set(ShellIntegrationExecutable.Zsh, ['-i']); diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index a8e86c1201e..6d867ef9568 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -583,7 +583,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess return; } this._logService.trace('IPty#pid'); - exec('lsof -OPln -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => { + exec('lsof -OPln -p ' + this._ptyProcess.pid + ' | grep cwd', { env: { ...process.env, LANG: 'en_US.UTF-8' } }, (error, stdout, stderr) => { if (!error && stdout !== '') { resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1)); } else { diff --git a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts index b6f76ccafbe..3f460194c30 100644 --- a/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/node/terminalEnvironment.test.ts @@ -25,14 +25,14 @@ suite('platform - terminalEnvironment', () => { suite('pwsh', () => { const expectedPs1 = process.platform === 'win32' - ? `${repoRoot}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1` - : `${repoRoot}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1`; + ? `try { . "${repoRoot}\\out\\vs\\workbench\\contrib\\terminal\\browser\\media\\shellIntegration.ps1" } catch {}` + : `. "${repoRoot}/out/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1"`; suite('should override args', () => { const enabledExpectedResult = Object.freeze({ newArgs: [ '-noexit', '-command', - `. "${expectedPs1}"` + expectedPs1 ], envMixin: { VSCODE_INJECTION: '1' @@ -63,7 +63,7 @@ suite('platform - terminalEnvironment', () => { '-l', '-noexit', '-command', - `. "${expectedPs1}"` + expectedPs1 ], envMixin: { VSCODE_INJECTION: '1' diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 0e438099b62..964644304d6 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -667,14 +667,14 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa return { ref: refOrLastSyncData, content }; } else { const lastSyncUserData: IUserData | null = refOrLastSyncData ? { ref: refOrLastSyncData.ref, content: refOrLastSyncData.syncData ? JSON.stringify(refOrLastSyncData.syncData) : null } : null; - return this.userDataSyncStoreService.read(this.resource, lastSyncUserData, this.syncHeaders); + return this.userDataSyncStoreService.read(this.resource, lastSyncUserData, undefined, this.syncHeaders); } } protected async updateRemoteUserData(content: string, ref: string | null): Promise { const machineId = await this.currentMachineIdPromise; const syncData: ISyncData = { version: this.version, machineId, content }; - ref = await this.userDataSyncStoreService.write(this.resource, JSON.stringify(syncData), ref, this.syncHeaders); + ref = await this.userDataSyncStoreService.write(this.resource, JSON.stringify(syncData), ref, undefined, this.syncHeaders); return { ref, syncData }; } diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index e902d4774f2..d244e00671a 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -480,7 +480,7 @@ export class UserDataSyncStoreTypeSynchronizer { private async doSync(userDataSyncStoreType: UserDataSyncStoreType, syncHeaders: IHeaders): Promise { // Read the global state from remote - const globalStateUserData = await this.userDataSyncStoreClient.read(SyncResource.GlobalState, null, syncHeaders); + const globalStateUserData = await this.userDataSyncStoreClient.readResource(SyncResource.GlobalState, null, syncHeaders); const remoteGlobalState = this.parseGlobalState(globalStateUserData) || { storage: {} }; // Update the sync store type @@ -489,7 +489,7 @@ export class UserDataSyncStoreTypeSynchronizer { // Write the global state to remote const machineId = await getServiceMachineId(this.environmentService, this.fileService, this.storageService); const syncDataToUpdate: ISyncData = { version: GLOBAL_STATE_DATA_VERSION, machineId, content: stringify(remoteGlobalState, false) }; - await this.userDataSyncStoreClient.write(SyncResource.GlobalState, JSON.stringify(syncDataToUpdate), globalStateUserData.ref, syncHeaders); + await this.userDataSyncStoreClient.writeResource(SyncResource.GlobalState, JSON.stringify(syncDataToUpdate), globalStateUserData.ref, syncHeaders); } private parseGlobalState({ content }: IUserData): IGlobalState | null { diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 6f6bf364d98..17ed95577de 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -156,7 +156,7 @@ export interface IResourceRefHandle { created: number; } -export type ServerResource = SyncResource | 'machines' | 'editSessions'; +export type ServerResource = SyncResource | 'machines' | 'editSessions' | 'profiles'; export type UserDataSyncStoreType = 'insiders' | 'stable'; export const IUserDataSyncStoreManagementService = createDecorator('IUserDataSyncStoreManagementService'); @@ -168,7 +168,9 @@ export interface IUserDataSyncStoreManagementService { getPreviousUserDataSyncStore(): Promise; } -export interface IUserDataSyncStoreClient { +export const IUserDataSyncStoreService = createDecorator('IUserDataSyncStoreService'); +export interface IUserDataSyncStoreService { + readonly _serviceBrand: undefined; readonly onDidChangeDonotMakeRequestsUntil: Event; readonly donotMakeRequestsUntil: Date | undefined; @@ -176,20 +178,13 @@ export interface IUserDataSyncStoreClient { readonly onTokenSucceed: Event; setAuthToken(token: string, type: string): void; - // Sync requests manifest(oldValue: IUserDataManifest | null, headers?: IHeaders): Promise; - read(resource: ServerResource, oldValue: IUserData | null, headers?: IHeaders): Promise; - write(resource: ServerResource, content: string, ref: string | null, headers?: IHeaders): Promise; + read(resource: ServerResource, oldValue: IUserData | null, profile?: string, headers?: IHeaders): Promise; + write(resource: ServerResource, content: string, ref: string | null, profile?: string, headers?: IHeaders): Promise; + delete(resource: ServerResource, ref: string | null, profile?: string): Promise; + getAllRefs(resource: ServerResource, profile?: string): Promise; + resolveContent(resource: ServerResource, ref: string, profile?: string, headers?: IHeaders): Promise; clear(): Promise; - delete(resource: ServerResource, ref: string | null): Promise; - - getAllRefs(resource: ServerResource): Promise; - resolveContent(resource: ServerResource, ref: string, headers?: IHeaders): Promise; -} - -export const IUserDataSyncStoreService = createDecorator('IUserDataSyncStoreService'); -export interface IUserDataSyncStoreService extends IUserDataSyncStoreClient { - readonly _serviceBrand: undefined; } export const IUserDataSyncBackupStoreService = createDecorator('IUserDataSyncBackupStoreService'); diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index c3fe6a3db6c..4104c13c6ad 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -12,6 +12,7 @@ import { Mimes } from 'vs/base/common/mime'; import { isWeb } from 'vs/base/common/platform'; import { ConfigurationSyncStore } from 'vs/base/common/product'; import { joinPath, relativePath } from 'vs/base/common/resources'; +import { join } from 'vs/base/common/path'; import { isObject, isString } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; @@ -23,7 +24,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { asJson, asTextOrError, IRequestService, isSuccess as isSuccessContext } from 'vs/platform/request/common/request'; import { getServiceMachineId } from 'vs/platform/externalServices/common/serviceMachineId'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { CONFIGURATION_SYNC_STORE_KEY, HEADER_EXECUTION_ID, HEADER_OPERATION_ID, IAuthenticationProvider, IResourceRefHandle, IUserData, IUserDataManifest, IUserDataSyncLogService, IUserDataSyncStore, IUserDataSyncStoreClient, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, ServerResource, SYNC_SERVICE_URL_TYPE, UserDataSyncErrorCode, UserDataSyncStoreError, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; +import { CONFIGURATION_SYNC_STORE_KEY, HEADER_EXECUTION_ID, HEADER_OPERATION_ID, IAuthenticationProvider, IResourceRefHandle, IUserData, IUserDataManifest, IUserDataSyncLogService, IUserDataSyncStore, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, ServerResource, SYNC_SERVICE_URL_TYPE, UserDataSyncErrorCode, UserDataSyncStoreError, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; const SYNC_PREVIOUS_STORE = 'sync.previous.store'; const DONOT_MAKE_REQUESTS_UNTIL_KEY = 'sync.donot-make-requests-until'; @@ -140,7 +141,7 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor } } -export class UserDataSyncStoreClient extends Disposable implements IUserDataSyncStoreClient { +export class UserDataSyncStoreClient extends Disposable { private userDataSyncStoreUrl: URI | undefined; @@ -230,12 +231,12 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync } } - async getAllRefs(resource: ServerResource): Promise { + async getAllResourceRefs(path: string): Promise { if (!this.userDataSyncStoreUrl) { throw new Error('No settings sync store url configured.'); } - const uri = joinPath(this.userDataSyncStoreUrl, 'resource', resource); + const uri = joinPath(this.userDataSyncStoreUrl, 'resource', path); const headers: IHeaders = {}; const context = await this.request(uri.toString(), { type: 'GET', headers }, [], CancellationToken.None); @@ -244,12 +245,12 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync return result.map(({ url, created }) => ({ ref: relativePath(uri, uri.with({ path: url }))!, created: created * 1000 /* Server returns in seconds */ })); } - async resolveContent(resource: ServerResource, ref: string, headers: IHeaders = {}): Promise { + async resolveResourceContent(path: string, ref: string, headers: IHeaders = {}): Promise { if (!this.userDataSyncStoreUrl) { throw new Error('No settings sync store url configured.'); } - const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource, ref).toString(); + const url = joinPath(this.userDataSyncStoreUrl, 'resource', path, ref).toString(); headers = { ...headers }; headers['Cache-Control'] = 'no-cache'; @@ -258,23 +259,23 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync return content; } - async delete(resource: ServerResource, ref: string | null): Promise { + async deleteResource(path: string, ref: string | null): Promise { if (!this.userDataSyncStoreUrl) { throw new Error('No settings sync store url configured.'); } - const url = ref !== null ? joinPath(this.userDataSyncStoreUrl, 'resource', resource, ref).toString() : joinPath(this.userDataSyncStoreUrl, 'resource', resource).toString(); + const url = ref !== null ? joinPath(this.userDataSyncStoreUrl, 'resource', path, ref).toString() : joinPath(this.userDataSyncStoreUrl, 'resource', path).toString(); const headers: IHeaders = {}; await this.request(url, { type: 'DELETE', headers }, [], CancellationToken.None); } - async read(resource: ServerResource, oldValue: IUserData | null, headers: IHeaders = {}): Promise { + async readResource(path: string, oldValue: IUserData | null, headers: IHeaders = {}): Promise { if (!this.userDataSyncStoreUrl) { throw new Error('No settings sync store url configured.'); } - const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource, 'latest').toString(); + const url = joinPath(this.userDataSyncStoreUrl, 'resource', path, 'latest').toString(); headers = { ...headers }; // Disable caching as they are cached by synchronisers headers['Cache-Control'] = 'no-cache'; @@ -306,12 +307,12 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync return userData; } - async write(resource: ServerResource, data: string, ref: string | null, headers: IHeaders = {}): Promise { + async writeResource(path: string, data: string, ref: string | null, headers: IHeaders = {}): Promise { if (!this.userDataSyncStoreUrl) { throw new Error('No settings sync store url configured.'); } - const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource).toString(); + const url = joinPath(this.userDataSyncStoreUrl, 'resource', path).toString(); headers = { ...headers }; headers['Content-Type'] = Mimes.text; if (ref) { @@ -549,6 +550,33 @@ export class UserDataSyncStoreService extends UserDataSyncStoreClient implements super(userDataSyncStoreManagementService.userDataSyncStore?.url, productService, requestService, logService, environmentService, fileService, storageService); this._register(userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => this.updateUserDataSyncStoreUrl(userDataSyncStoreManagementService.userDataSyncStore?.url))); } + + getAllRefs(resource: ServerResource, profile?: string): Promise { + return this.getAllResourceRefs(profile ? this.getProfileResource(resource, profile) : resource); + } + + read(resource: ServerResource, oldValue: IUserData | null, profile?: string, headers?: IHeaders): Promise { + return this.readResource(profile ? this.getProfileResource(resource, profile) : resource, oldValue, headers); + } + + write(resource: ServerResource, content: string, ref: string | null, profile?: string, headers?: IHeaders): Promise { + return this.writeResource(profile ? this.getProfileResource(resource, profile) : resource, content, ref, headers); + } + + delete(resource: ServerResource, ref: string | null, profile?: string): Promise { + return this.deleteResource(profile ? this.getProfileResource(resource, profile) : resource, ref); + } + + resolveContent(resource: ServerResource, ref: string, profile?: string, headers?: IHeaders): Promise { + return this.resolveResourceContent(profile ? this.getProfileResource(resource, profile) : resource, ref, headers); + } + + private getProfileResource(resource: ServerResource, profile: string): string { + if (resource === 'profiles') { + throw new Error(`Invalid Resource Argument: ${resource}`); + } + return join('profiles', profile, resource); + } } export class RequestsSession { diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index 2f29d96f1ab..fde2dc5ed5d 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -20,9 +20,8 @@ import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle import { ILogService } from 'vs/platform/log/common/log'; import { StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IApplicationStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; -import { ICodeWindow } from 'vs/platform/window/electron-main/window'; import { IRecent, IRecentFile, IRecentFolder, IRecentlyOpened, IRecentWorkspace, isRecentFile, isRecentFolder, isRecentWorkspace, restoreRecentlyOpened, toStoreData } from 'vs/platform/workspaces/common/workspaces'; -import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; export const IWorkspacesHistoryMainService = createDecorator('workspacesHistoryMainService'); @@ -34,7 +33,7 @@ export interface IWorkspacesHistoryMainService { readonly onDidChangeRecentlyOpened: CommonEvent; addRecentlyOpened(recents: IRecent[]): Promise; - getRecentlyOpened(include?: ICodeWindow): Promise; + getRecentlyOpened(): Promise; removeRecentlyOpened(paths: URI[]): Promise; clearRecentlyOpened(): Promise; } @@ -162,31 +161,10 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa this._onDidChangeRecentlyOpened.fire(); } - async getRecentlyOpened(include?: ICodeWindow): Promise { + async getRecentlyOpened(): Promise { const workspaces: Array = []; const files: IRecentFile[] = []; - // Add current workspace to beginning if set - if (include) { - const currentWorkspace = include.config?.workspace; - if (isWorkspaceIdentifier(currentWorkspace) && !this.workspacesManagementMainService.isUntitledWorkspace(currentWorkspace)) { - workspaces.push({ workspace: currentWorkspace, remoteAuthority: include.remoteAuthority }); - } else if (isSingleFolderWorkspaceIdentifier(currentWorkspace)) { - workspaces.push({ folderUri: currentWorkspace.uri, remoteAuthority: include.remoteAuthority }); - } - } - - // Add currently files to open to the beginning if any - const currentFiles = include?.config?.filesToOpenOrCreate; - if (currentFiles) { - for (const currentFile of currentFiles) { - const fileUri = currentFile.fileUri; - if (fileUri && this.indexOfFile(files, fileUri) === -1) { - files.push({ fileUri }); - } - } - } - await this.addEntriesFromStorage(workspaces, files); return { workspaces, files }; diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index cacee0ee330..de17f98befb 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -55,7 +55,7 @@ export class WorkspacesMainService implements AddFirstParameterToFunctions { - return this.workspacesHistoryMainService.getRecentlyOpened(this.windowsMainService.getWindowById(windowId)); + return this.workspacesHistoryMainService.getRecentlyOpened(); } addRecentlyOpened(windowId: number, recents: IRecent[]): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadTesting.ts b/src/vs/workbench/api/browser/mainThreadTesting.ts index fb9a562b3d0..e21387242da 100644 --- a/src/vs/workbench/api/browser/mainThreadTesting.ts +++ b/src/vs/workbench/api/browser/mainThreadTesting.ts @@ -173,7 +173,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh canRefresh, refreshTests: token => this.proxy.$refreshTests(controllerId, token), configureRunProfile: id => this.proxy.$configureRunProfile(controllerId, id), - runTests: (req, token) => this.proxy.$runControllerTests(req, token), + runTests: (reqs, token) => this.proxy.$runControllerTests(reqs, token), expandTest: (testId, levels) => this.proxy.$expandTest(testId, isFinite(levels) ? levels : -1), }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index ed17dcc5b4c..615572cdb03 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2173,7 +2173,7 @@ export const enum ExtHostTestingResource { } export interface ExtHostTestingShape { - $runControllerTests(req: RunTestForControllerRequest, token: CancellationToken): Promise; + $runControllerTests(req: RunTestForControllerRequest[], token: CancellationToken): Promise<{ error?: string }[]>; $cancelExtensionTestRun(runId: string | undefined): void; /** Handles a diff of tests, as a result of a subscribeToDiffs() call */ $acceptDiff(diff: TestsDiffOp.Serialized[]): void; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index ac865608116..2eaaced1a32 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -280,10 +280,18 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme public async getExtension(extensionId: string): Promise { const ext = await this._mainThreadExtensionsProxy.$getExtension(extensionId); + let browserNlsBundleUris: { [language: string]: URI } | undefined; + if (ext?.browserNlsBundleUris) { + browserNlsBundleUris = {}; + for (const language of Object.keys(ext.browserNlsBundleUris)) { + browserNlsBundleUris[language] = URI.revive(ext.browserNlsBundleUris[language]); + } + } return ext && { ...ext, identifier: new ExtensionIdentifier(ext.identifier.value), extensionLocation: URI.revive(ext.extensionLocation), + browserNlsBundleUris }; } @@ -465,7 +473,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); return Promise.all([ - this._loadCommonJSModule(extensionDescription.identifier, joinPath(extensionDescription.extensionLocation, entryPoint), activationTimesBuilder), + this._loadCommonJSModule(extensionDescription, joinPath(extensionDescription.extensionLocation, entryPoint), activationTimesBuilder), this._loadExtensionContext(extensionDescription) ]).then(values => { performance.mark(`code/extHost/willActivateExtension/${extensionDescription.identifier.value}`); @@ -923,7 +931,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme protected abstract _beforeAlmostReadyToRunExtensions(): Promise; protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined; - protected abstract _loadCommonJSModule(extensionId: ExtensionIdentifier | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise; + protected abstract _loadCommonJSModule(extensionId: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise; public abstract $setRemoteEnvironment(env: { [key: string]: string | null }): Promise; } diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts index 6cc843c39dc..cd0ab1203ed 100644 --- a/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -348,10 +348,13 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { const document = this._extHostNotebook.getNotebookDocument(URI.revive(uri)); const cell = document.getCell(cellHandle); if (cell) { - this._onDidChangeCellExecutionState.fire({ - cell: cell.apiCell, - state: state ? extHostTypeConverters.NotebookCellExecutionState.to(state) : ExtHostNotebookCellExecutionState.Idle - }); + const newState = state ? extHostTypeConverters.NotebookCellExecutionState.to(state) : ExtHostNotebookCellExecutionState.Idle; + if (newState !== undefined) { + this._onDidChangeCellExecutionState.fire({ + cell: cell.apiCell, + state: newState + }); + } } } diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index 559d09d0aa0..2f0a2caa370 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -22,7 +22,7 @@ import * as Convert from 'vs/workbench/api/common/extHostTypeConverters'; import { TestRunProfileKind, TestRunRequest } from 'vs/workbench/api/common/extHostTypes'; import { TestId, TestIdPathParts, TestPosition } from 'vs/workbench/contrib/testing/common/testId'; import { InvalidTestItemError } from 'vs/workbench/contrib/testing/common/testItemCollection'; -import { AbstractIncrementalTestCollection, CoverageDetails, IFileCoverage, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, ITestItem, RunTestForControllerRequest, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes'; +import { AbstractIncrementalTestCollection, CoverageDetails, IFileCoverage, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, ITestItem, RunTestForControllerRequest, RunTestForControllerResult, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes'; import type * as vscode from 'vscode'; interface ControllerInfo { @@ -227,16 +227,20 @@ export class ExtHostTesting implements ExtHostTestingShape { * providers to be run. * @override */ - public async $runControllerTests(req: RunTestForControllerRequest, token: CancellationToken): Promise { + public async $runControllerTests(reqs: RunTestForControllerRequest[], token: CancellationToken): Promise { + return Promise.all(reqs.map(req => this.runControllerTestRequest(req, token))); + } + + public async runControllerTestRequest(req: RunTestForControllerRequest, token: CancellationToken): Promise { const lookup = this.controllers.get(req.controllerId); if (!lookup) { - return; + return {}; } const { collection, profiles } = lookup; const profile = profiles.get(req.profileId); if (!profile) { - return; + return {}; } const includeTests = req.testIds @@ -251,7 +255,7 @@ export class ExtHostTesting implements ExtHostTestingShape { )); if (!includeTests.length) { - return; + return {}; } const publicReq = new TestRunRequest( @@ -268,6 +272,9 @@ export class ExtHostTesting implements ExtHostTestingShape { try { await profile.runHandler(publicReq, token); + return {}; + } catch (e) { + return { error: String(e) }; } finally { if (tracker.isRunning && !token.isCancellationRequested) { await Event.toPromise(tracker.onEnd); diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index c71c6adcd1e..24a67b8d68c 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1538,13 +1538,14 @@ export namespace NotebookCellExecutionSummary { } export namespace NotebookCellExecutionState { - export function to(state: notebooks.NotebookCellExecutionState): vscode.NotebookCellExecutionState { - if (state === notebooks.NotebookCellExecutionState.Executing) { - return types.NotebookCellExecutionState.Executing; + export function to(state: notebooks.NotebookCellExecutionState): vscode.NotebookCellExecutionState | undefined { + if (state === notebooks.NotebookCellExecutionState.Unconfirmed) { + return types.NotebookCellExecutionState.Pending; } else if (state === notebooks.NotebookCellExecutionState.Pending) { - return types.NotebookCellExecutionState.Pending; - } else if (state === notebooks.NotebookCellExecutionState.Unconfirmed) { - return types.NotebookCellExecutionState.Pending; + // Since the (proposed) extension API doesn't have the distinction between Unconfirmed and Pending, we don't want to fire an update for Pending twice + return undefined; + } else if (state === notebooks.NotebookCellExecutionState.Executing) { + return types.NotebookCellExecutionState.Executing; } else { throw new Error(`Unknown state: ${state}`); } diff --git a/src/vs/workbench/api/common/extensionHostMain.ts b/src/vs/workbench/api/common/extensionHostMain.ts index 0eabc9e29cc..6328360e0b3 100644 --- a/src/vs/workbench/api/common/extensionHostMain.ts +++ b/src/vs/workbench/api/common/extensionHostMain.ts @@ -120,7 +120,14 @@ export class ExtensionHostMain { } private static _transform(initData: IExtensionHostInitData, rpcProtocol: RPCProtocol): IExtensionHostInitData { - initData.allExtensions.forEach((ext) => (ext).extensionLocation = URI.revive(rpcProtocol.transformIncomingURIs(ext.extensionLocation))); + initData.allExtensions.forEach((ext) => { + (ext).extensionLocation = URI.revive(rpcProtocol.transformIncomingURIs(ext.extensionLocation)); + const browserNlsBundleUris: { [language: string]: URI } = {}; + if (ext.browserNlsBundleUris) { + Object.keys(ext.browserNlsBundleUris).forEach(lang => browserNlsBundleUris[lang] = URI.revive(rpcProtocol.transformIncomingURIs(ext.browserNlsBundleUris![lang]))); + (ext).browserNlsBundleUris = browserNlsBundleUris; + } + }); initData.environment.appRoot = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appRoot)); const extDevLocs = initData.environment.extensionDevelopmentLocationURI; if (extDevLocs) { diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 352ce260dd8..c15b76ff78d 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -12,7 +12,7 @@ import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHost import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes'; import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer'; import { realpathSync } from 'vs/base/node/extpath'; @@ -89,7 +89,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { return extensionDescription.main; } - protected _loadCommonJSModule(extensionId: ExtensionIdentifier | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected _loadCommonJSModule(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { if (module.scheme !== Schemas.file) { throw new Error(`Cannot load URI: '${module}', must be of file-scheme`); } @@ -97,16 +97,17 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { activationTimesBuilder.codeLoadingStart(); this._logService.trace(`ExtensionService#loadCommonJSModule ${module.toString(true)}`); this._logService.flush(); + const extensionId = extension?.identifier.value; try { if (extensionId) { - performance.mark(`code/extHost/willLoadExtensionCode/${extensionId.value}`); + performance.mark(`code/extHost/willLoadExtensionCode/${extensionId}`); } r = require.__$__nodeRequire(module.fsPath); } catch (e) { return Promise.reject(e); } finally { if (extensionId) { - performance.mark(`code/extHost/didLoadExtensionCode/${extensionId.value}`); + performance.mark(`code/extHost/didLoadExtensionCode/${extensionId}`); } activationTimesBuilder.codeLoadingStop(); } diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index cc5f3b090fc..aceb7ba278a 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -8,10 +8,11 @@ import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHost import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { URI } from 'vs/base/common/uri'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes'; import { timeout } from 'vs/base/common/async'; import { ExtHostConsoleForwarder } from 'vs/workbench/api/worker/extHostConsoleForwarder'; +import { Language } from 'vs/base/common/platform'; class WorkerRequireInterceptor extends RequireInterceptor { @@ -55,10 +56,11 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { return extensionDescription.browser; } - protected async _loadCommonJSModule(extensionId: ExtensionIdentifier | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected async _loadCommonJSModule(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { module = module.with({ path: ensureSuffix(module.path, '.js') }); + const extensionId = extension?.identifier.value; if (extensionId) { - performance.mark(`code/extHost/willFetchExtensionCode/${extensionId.value}`); + performance.mark(`code/extHost/willFetchExtensionCode/${extensionId}`); } // First resolve the extension entry point URI to something we can load using `fetch` @@ -67,7 +69,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { const browserUri = URI.revive(await this._mainThreadExtensionsProxy.$asBrowserUri(module)); const response = await fetch(browserUri.toString(true)); if (extensionId) { - performance.mark(`code/extHost/didFetchExtensionCode/${extensionId.value}`); + performance.mark(`code/extHost/didFetchExtensionCode/${extensionId}`); } if (response.status !== 200) { @@ -85,7 +87,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { initFn = new Function('module', 'exports', 'require', fullSource); } catch (err) { if (extensionId) { - console.error(`Loading code for extension ${extensionId.value} failed: ${err.message}`); + console.error(`Loading code for extension ${extensionId} failed: ${err.message}`); } else { console.error(`Loading code failed: ${err.message}`); } @@ -94,10 +96,17 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { throw err; } + const strings: { [key: string]: string[] } = await this.fetchTranslatedStrings(extension); + // define commonjs globals: `module`, `exports`, and `require` const _exports = {}; const _module = { exports: _exports }; const _require = (request: string) => { + // In order to keep vscode-nls synchronous, we prefetched the translations above + // and then return them here when the extension is loaded. + if (request === 'vscode-nls-web-data') { + return strings; + } const result = this._fakeModules!.getModule(request, module); if (result === undefined) { throw new Error(`Cannot load module '${request}'`); @@ -108,13 +117,13 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { try { activationTimesBuilder.codeLoadingStart(); if (extensionId) { - performance.mark(`code/extHost/willLoadExtensionCode/${extensionId.value}`); + performance.mark(`code/extHost/willLoadExtensionCode/${extensionId}`); } initFn(_module, _exports, _require); return (_module.exports !== _exports ? _module.exports : _exports); } finally { if (extensionId) { - performance.mark(`code/extHost/didLoadExtensionCode/${extensionId.value}`); + performance.mark(`code/extHost/didLoadExtensionCode/${extensionId}`); } activationTimesBuilder.codeLoadingStop(); } @@ -135,6 +144,44 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await timeout(10); } } + + private async fetchTranslatedStrings(extension: IExtensionDescription | null): Promise<{ [key: string]: string[] }> { + let strings: { [key: string]: string[] } = {}; + if (!extension) { + return {}; + } + const translationsUri = Language.isDefaultVariant() + // If we are in the default variant, load the translations for en only. + ? extension.browserNlsBundleUris?.en + // Otherwise load the translations for the current locale with English as a fallback. + : extension.browserNlsBundleUris?.[Language.value()] ?? extension.browserNlsBundleUris?.en; + if (extension && translationsUri) { + try { + const response = await fetch(translationsUri.toString(true)); + if (!response.ok) { + throw new Error(await response.text()); + } + strings = await response.json(); + } catch (e) { + try { + console.error(`Failed to load translations for ${extension.identifier.value} from ${translationsUri}: ${e.message}`); + const englishStrings = extension.browserNlsBundleUris?.en; + if (englishStrings) { + const response = await fetch(englishStrings.toString(true)); + if (!response.ok) { + throw new Error(await response.text()); + } + strings = await response.json(); + } + throw new Error('No English strings found'); + } catch (e) { + // TODO what should this do? We really shouldn't ever be here... + console.error(e); + } + } + } + return strings; + } } function ensureSuffix(path: string, suffix: string): string { diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 8bc290a1655..1a73aa0b4c5 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -121,13 +121,9 @@ export class ResourcesDropHandler { } // Add external ones to recently open list unless dropped resource is a workspace - // and only for resources that are outside of the currently opened workspace const externalLocalFiles = coalesce(editors.filter(editor => editor.isExternal && editor.resource?.scheme === Schemas.file).map(editor => editor.resource)); if (externalLocalFiles.length) { - this.workspacesService.addRecentlyOpened(externalLocalFiles - .filter(resource => !this.contextService.isInsideWorkspace(resource)) - .map(resource => ({ fileUri: resource })) - ); + this.workspacesService.addRecentlyOpened(externalLocalFiles.map(resource => ({ fileUri: resource }))); } // Open in Editor diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 753c32d24c0..b3d2c5104fe 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -429,32 +429,29 @@ export class ContextScopedSuggestEnabledInputWithHistory extends SuggestEnabledI // Override styles in selections.ts registerThemingParticipant((theme, collector) => { - let selectionColor = theme.getColor(selectionBackground); - if (selectionColor) { - selectionColor = selectionColor.transparent(0.4); + const selectionBackgroundColor = theme.getColor(selectionBackground); + + if (selectionBackgroundColor) { + // Override inactive selection bg + const inputBackgroundColor = theme.getColor(inputBackground); + if (inputBackgroundColor) { + collector.addRule(`.suggest-input-container .monaco-editor .selected-text { background-color: ${inputBackgroundColor.transparent(0.4)}; }`); + } + + // Override selected fg + const inputForegroundColor = theme.getColor(inputForeground); + if (inputForegroundColor) { + collector.addRule(`.suggest-input-container .monaco-editor .view-line span.inline-selected-text { color: ${inputForegroundColor}; }`); + } + + const backgroundColor = theme.getColor(inputBackground); + if (backgroundColor) { + collector.addRule(`.suggest-input-container .monaco-editor-background { background-color: ${backgroundColor}; } `); + } + collector.addRule(`.suggest-input-container .monaco-editor .focused .selected-text { background-color: ${selectionBackgroundColor}; }`); } else { - selectionColor = theme.getColor(editorSelectionBackground); - } - - if (selectionColor) { - collector.addRule(`.suggest-input-container .monaco-editor .focused .selected-text { background-color: ${selectionColor}; }`); - } - - // Override inactive selection bg - const inputBackgroundColor = theme.getColor(inputBackground); - if (inputBackgroundColor) { - collector.addRule(`.suggest-input-container .monaco-editor .selected-text { background-color: ${inputBackgroundColor.transparent(0.4)}; }`); - } - - // Override selected fg - const inputForegroundColor = theme.getColor(inputForeground); - if (inputForegroundColor) { - collector.addRule(`.suggest-input-container .monaco-editor .view-line span.inline-selected-text { color: ${inputForegroundColor}; }`); - } - - const backgroundColor = theme.getColor(inputBackground); - if (backgroundColor) { - collector.addRule(`.suggest-input-container .monaco-editor-background { background-color: ${backgroundColor}; } `); + // Use editor selection color if theme has not set a selection background color + collector.addRule(`.suggest-input-container .monaco-editor .focused .selected-text { background-color: ${theme.getColor(editorSelectionBackground)}; }`); } }); diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index 5e00363d505..35a3c09535d 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -287,7 +287,7 @@ export class BreakpointsView extends ViewPane { const dbg = currentType ? this.debugService.getAdapterManager().getDebugger(currentType) : undefined; const message = dbg?.uiMessages && dbg.uiMessages[DebuggerUiMessage.UnverifiedBreakpoints]; const debuggerHasUnverifiedBps = message && this.debugService.getModel().getBreakpoints().filter(bp => { - if (bp.verified) { + if (bp.verified || !bp.enabled) { return false; } diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 0cf0497bec2..27bb4016459 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -6,7 +6,7 @@ import * as aria from 'vs/base/browser/ui/aria/aria'; import { Action, IAction } from 'vs/base/common/actions'; import { distinct } from 'vs/base/common/arrays'; -import { raceTimeout, RunOnceScheduler } from 'vs/base/common/async'; +import { Queue, raceTimeout, RunOnceScheduler } from 'vs/base/common/async'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isErrorWithActions } from 'vs/base/common/errorMessage'; import * as errors from 'vs/base/common/errors'; @@ -825,6 +825,7 @@ export class DebugService implements IDebugService { return Promise.all(sessions.map(s => disconnect ? s.disconnect(undefined, suspend) : s.terminate())); } + private variableSubstitutionQueue = new Queue(); private async substituteVariables(launch: ILaunch | undefined, config: IConfig): Promise { const dbg = this.adapterManager.getDebugger(config.type); if (dbg) { @@ -838,7 +839,8 @@ export class DebugService implements IDebugService { } } try { - return await dbg.substituteVariables(folder, config); + // Variable substitution can require user interaction, so only one of these should be running at a time. + return this.variableSubstitutionQueue.queue(() => dbg.substituteVariables(folder, config)); } catch (err) { this.showError(err.message, undefined, !!launch?.getConfiguration(config.name)); return undefined; // bail out diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index aefd3c5c6b1..65cb8246dd3 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -99,7 +99,10 @@ export class VariablesView extends ViewPane { // Automatically expand the first non-expensive scope const scopes = await stackFrame.getScopes(); const toExpand = scopes.find(s => !s.expensive); - if (toExpand) { + + // A race condition could be present causing the scopes here to be different from the scopes that the tree just retrieved. + // If that happened, don't try to reveal anything, it will be straightened out on the next update + if (toExpand && this.tree.hasNode(toExpand)) { this.autoExpandedScopes.add(toExpand.getId()); await this.tree.expand(toExpand); } diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts index c8c9b8f437f..e4564cf9958 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts @@ -77,7 +77,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes throw new Error('Please sign in to store your edit session.'); } - return this.storeClient!.write('editSessions', JSON.stringify(editSession), null, createSyncHeaders(generateUuid())); + return this.storeClient!.writeResource('editSessions', JSON.stringify(editSession), null, createSyncHeaders(generateUuid())); } /** @@ -96,9 +96,9 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes const headers = createSyncHeaders(generateUuid()); try { if (ref !== undefined) { - content = await this.storeClient?.resolveContent('editSessions', ref, headers); + content = await this.storeClient?.resolveResourceContent('editSessions', ref, headers); } else { - const result = await this.storeClient?.read('editSessions', null, headers); + const result = await this.storeClient?.readResource('editSessions', null, headers); content = result?.content; ref = result?.ref; } @@ -117,7 +117,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes } try { - await this.storeClient?.delete('editSessions', ref); + await this.storeClient?.deleteResource('editSessions', ref); } catch (ex) { this.logService.error(ex); } @@ -130,7 +130,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes } try { - return this.storeClient?.getAllRefs('editSessions') ?? []; + return this.storeClient?.getAllResourceRefs('editSessions') ?? []; } catch (ex) { this.logService.error(ex); } @@ -400,7 +400,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes }); if (result.confirmed) { if (result.checkboxChecked) { - that.storeClient?.delete('editSessions', null); + that.storeClient?.deleteResource('editSessions', null); } that.clearAuthenticationPreference(); } diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit.ts index 7209af8ccaf..851e2d0c3f3 100644 --- a/src/vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/remoteExtensionsInit.ts @@ -83,7 +83,7 @@ export class RemoteExtensionsInitializerContribution implements IWorkbenchContri const userDataSyncStoreClient = this.instantiationService.createInstance(UserDataSyncStoreClient, this.userDataSyncStoreManagementService.userDataSyncStore.url); userDataSyncStoreClient.setAuthToken(session.accessToken, resolvedAuthority.options.authenticationSession.providerId); - const userData = await userDataSyncStoreClient.read(SyncResource.Extensions, null); + const userData = await userDataSyncStoreClient.readResource(SyncResource.Extensions, null); const serviceCollection = new ServiceCollection(); serviceCollection.set(IExtensionManagementService, remoteExtensionManagementServer.extensionManagementService); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts index 2f5d35ba93f..3d63457554d 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async'; -import { INotebookEditor, CellFindMatch, CellEditState, CellFindMatchWithIndex, OutputFindMatch, ICellModelDecorations, ICellModelDeltaDecorations, INotebookDeltaDecoration } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditor, CellFindMatch, CellEditState, CellFindMatchWithIndex, OutputFindMatch, ICellModelDecorations, ICellModelDeltaDecorations, INotebookDeltaDecoration, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { Range } from 'vs/editor/common/core/range'; import { FindDecorations } from 'vs/editor/contrib/find/browser/findDecorations'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; @@ -88,6 +88,34 @@ export class FindModel extends Disposable { }; } + refreshCurrentMatch(focus: { cell: ICellViewModel; range: Range }) { + const findMatchIndex = this.findMatches.findIndex(match => match.cell === focus.cell); + + if (findMatchIndex === -1) { + return; + } + + const findMatch = this.findMatches[findMatchIndex]; + const index = findMatch.matches.slice(0, findMatch.modelMatchCount).findIndex(match => (match as FindMatch).range.intersectRanges(focus.range) !== null); + + if (index === undefined) { + return; + } + + const matchesBefore = findMatchIndex === 0 ? 0 : (this._findMatchesStarts?.getPrefixSum(findMatchIndex - 1) ?? 0); + this._currentMatch = matchesBefore + index; + + this.highlightCurrentFindMatchDecoration(findMatchIndex, index).then(offset => { + this.revealCellRange(findMatchIndex, index, offset); + + this._state.changeMatchInfo( + this._currentMatch, + this._findMatches.reduce((p, c) => p + c.matches.length, 0), + undefined + ); + }); + } + find(option: { previous: boolean } | { index: number }) { if (!this.findMatches.length) { return; @@ -189,20 +217,28 @@ export class FindModel extends Disposable { return; } + const findFirstMatchAfterCellIndex = (cellIndex: number) => { + const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= cellIndex); + this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection)); + }; + if (this._currentMatch === -1) { // no active current match - this.set(findMatches, false); - return; + if (this._notebookEditor.getLength() === 0) { + this.set(findMatches, false); + return; + } else { + const focus = this._notebookEditor.getFocus().start; + findFirstMatchAfterCellIndex(focus); + this.set(findMatches, false); + return; + } } const oldCurrIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); const oldCurrCell = this._findMatches[oldCurrIndex.index].cell; const oldCurrMatchCellIndex = this._notebookEditor.getCellIndex(oldCurrCell); - const findFirstMatchAfterCellIndex = (cellIndex: number) => { - const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= cellIndex); - this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection)); - }; if (oldCurrMatchCellIndex < 0) { // the cell containing the active match is deleted @@ -225,7 +261,7 @@ export class FindModel extends Disposable { return; } - // the cell is a markdown cell in editing mode or a code cell, both should have monaco editor rendered + // the cell is a markup cell in editing mode or a code cell, both should have monaco editor rendered if (!this._currentMatchDecorations) { // no current highlight decoration diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFind.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFind.ts index 50fe4315bf0..e8f1ecef273 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFind.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFind.ts @@ -18,7 +18,7 @@ import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { NotebookFindWidget } from 'vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget'; +import { IShowNotebookFindWidgetOptions, NotebookFindWidget } from 'vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget'; import { getNotebookEditorFromEditorPane } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -92,21 +92,27 @@ function notebookContainsTextModel(uri: URI, textModel: ITextModel) { return false; } -function getSearchString(editor: ICodeEditor, opts: IFindStartOptions) { +function getSearchStringOptions(editor: ICodeEditor, opts: IFindStartOptions) { // Get the search string result, following the same logic in _start function in 'vs/editor/contrib/find/browser/findController' - let searchString = ''; if (opts.seedSearchStringFromSelection === 'single') { const selectionSearchString = getSelectionSearchString(editor, opts.seedSearchStringFromSelection, opts.seedSearchStringFromNonEmptySelection); if (selectionSearchString) { - searchString = selectionSearchString; + return { + searchString: selectionSearchString, + selection: editor.getSelection() + }; } } else if (opts.seedSearchStringFromSelection === 'multiple' && !opts.updateSearchScope) { const selectionSearchString = getSelectionSearchString(editor, opts.seedSearchStringFromSelection); if (selectionSearchString) { - searchString = selectionSearchString; + return { + searchString: selectionSearchString, + selection: editor.getSelection() + }; } } - return searchString; + + return undefined; } @@ -118,6 +124,10 @@ StartFindAction.addImplementation(100, (accessor: ServicesAccessor, codeEditor: return false; } + if (!codeEditor.hasModel()) { + return false; + } + if (!editor.hasEditorFocus() && !editor.hasWebviewFocus()) { const codeEditorService = accessor.get(ICodeEditorService); // check if the active pane contains the active text editor @@ -131,7 +141,7 @@ StartFindAction.addImplementation(100, (accessor: ServicesAccessor, codeEditor: const controller = editor.getContribution(NotebookFindWidget.id); - const searchString = getSearchString(codeEditor, { + const searchStringOptions = getSearchStringOptions(codeEditor, { forceRevealReplace: false, seedSearchStringFromSelection: codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection !== 'never' ? 'single' : 'none', seedSearchStringFromNonEmptySelection: codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection === 'selection', @@ -142,7 +152,19 @@ StartFindAction.addImplementation(100, (accessor: ServicesAccessor, codeEditor: loop: codeEditor.getOption(EditorOption.find).loop }); - controller.show(searchString); + let options: IShowNotebookFindWidgetOptions | undefined = undefined; + const uri = codeEditor.getModel().uri; + const data = CellUri.parse(uri); + if (searchStringOptions?.selection && data) { + const cell = editor.getCellByHandle(data.handle); + if (cell) { + options = { + searchStringSeededFrom: { cell, range: searchStringOptions.selection }, + }; + } + } + + controller.show(searchStringOptions?.searchString, options); return true; }); @@ -154,9 +176,13 @@ StartFindReplaceAction.addImplementation(100, (accessor: ServicesAccessor, codeE return false; } + if (!codeEditor.hasModel()) { + return false; + } + const controller = editor.getContribution(NotebookFindWidget.id); - const searchString = getSearchString(codeEditor, { + const searchStringOptions = getSearchStringOptions(codeEditor, { forceRevealReplace: false, seedSearchStringFromSelection: codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection !== 'never' ? 'single' : 'none', seedSearchStringFromNonEmptySelection: codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection === 'selection', @@ -168,7 +194,7 @@ StartFindReplaceAction.addImplementation(100, (accessor: ServicesAccessor, codeE }); if (controller) { - controller.replace(searchString); + controller.replace(searchStringOptions?.searchString); return true; } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts index 9c38190c342..df3bc2f48ba 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts @@ -23,7 +23,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { NotebookFindFilters } from 'vs/workbench/contrib/notebook/browser/contrib/find/findFilters'; import { FindModel } from 'vs/workbench/contrib/notebook/browser/contrib/find/findModel'; import { SimpleFindReplaceWidget } from 'vs/workbench/contrib/notebook/browser/contrib/find/notebookFindReplaceWidget'; -import { CellEditState, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; const FIND_HIDE_TRANSITION = 'find-hide-transition'; @@ -37,6 +37,7 @@ export interface IShowNotebookFindWidgetOptions { matchCase?: boolean; matchIndex?: number; focus?: boolean; + searchStringSeededFrom?: { cell: ICellViewModel; range: Range }; } export class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEditorContribution { @@ -214,6 +215,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote protected onFindInputFocusTrackerBlur(): void { } override async show(initialInput?: string, options?: IShowNotebookFindWidgetOptions): Promise { + const searchStringUpdate = this._state.searchString !== initialInput; super.show(initialInput, options); this._state.change({ searchString: initialInput ?? '', isRevealed: true }, false); @@ -226,6 +228,10 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote this._findInput.select(); } + if (!searchStringUpdate && options?.searchStringSeededFrom) { + this._findModel.refreshCurrentMatch(options.searchStringSeededFrom); + } + if (this._showTimeout === null) { if (this._hideTimeout !== null) { window.clearTimeout(this._hideTimeout); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 9c4bcd48dae..a693a2ae1f4 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -869,9 +869,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD deltaCellOutputContainerClassNames(diffSide: DiffSide, cellId: string, added: string[], removed: string[]) { if (diffSide === DiffSide.Original) { - this._originalWebview?.deltaCellOutputContainerClassNames(cellId, added, removed); + this._originalWebview?.deltaCellContainerClassNames(cellId, added, removed); } else { - this._modifiedWebview?.deltaCellOutputContainerClassNames(cellId, added, removed); + this._modifiedWebview?.deltaCellContainerClassNames(cellId, added, removed); } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 9b245482c3d..e108d0a0c55 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -180,7 +180,7 @@ export interface CodeCellLayoutChangeEvent { font?: FontInfo; } -export interface MarkdownCellLayoutInfo { +export interface MarkupCellLayoutInfo { readonly fontInfo: FontInfo | null; readonly editorWidth: number; readonly editorHeight: number; @@ -196,7 +196,7 @@ export enum CellLayoutContext { Fold } -export interface MarkdownCellLayoutChangeEvent { +export interface MarkupCellLayoutChangeEvent { font?: FontInfo; outerWidth?: number; editorHeight?: number; @@ -675,7 +675,7 @@ export interface INotebookEditorDelegate extends INotebookEditor { * Hide the inset in the webview layer without removing it */ hideInset(output: IDisplayOutputViewModel): void; - deltaCellOutputContainerClassNames(cellId: string, added: string[], removed: string[]): void; + deltaCellContainerClassNames(cellId: string, added: string[], removed: string[]): void; } export interface IActiveNotebookEditorDelegate extends INotebookEditorDelegate { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index f802ab61bdc..c7e24eb8382 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1855,6 +1855,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD // The notebook editor doesn't have focus yet if (!this.hasEditorFocus()) { this.focusContainer(); + // trigger editor to update as FocusTracker might not emit focus change event + this.updateEditorFocus(); } if (element && element.focusMode === CellFocusMode.Editor) { @@ -2104,8 +2106,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD return ret; } - deltaCellOutputContainerClassNames(cellId: string, added: string[], removed: string[]) { - this._webview?.deltaCellOutputContainerClassNames(cellId, added, removed); + deltaCellContainerClassNames(cellId: string, added: string[], removed: string[]) { + this._webview?.deltaCellContainerClassNames(cellId, added, removed); } changeModelDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts index 845cc72df8e..f5ad835726c 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts @@ -13,7 +13,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { CellEditType, CellUri, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata, NotebookTextModelWillAddRemoveEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellExecutionUpdateType, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; -import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionStateChangedEvent, ICellExecutionStateUpdate, INotebookCellExecution, INotebookExecutionStateService, INotebookFailStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; +import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionStateChangedEvent, ICellExecutionStateUpdate, IFailedCellInfo, INotebookCellExecution, INotebookExecutionStateService, INotebookFailStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; export class NotebookExecutionStateService extends Disposable implements INotebookExecutionStateService { @@ -22,7 +22,7 @@ export class NotebookExecutionStateService extends Disposable implements INotebo private readonly _executions = new ResourceMap>(); private readonly _notebookListeners = new ResourceMap(); private readonly _cellListeners = new ResourceMap(); - private readonly _lastFailedCells = new ResourceMap(); + private readonly _lastFailedCells = new ResourceMap(); private readonly _onDidChangeCellExecution = this._register(new Emitter()); onDidChangeCellExecution = this._onDidChangeCellExecution.event; @@ -39,7 +39,8 @@ export class NotebookExecutionStateService extends Disposable implements INotebo } getLastFailedCellForNotebook(notebook: URI): number | undefined { - return this._lastFailedCells.get(notebook); + const failedCell = this._lastFailedCells.get(notebook); + return failedCell?.visible ? failedCell.cellHandle : undefined; } forceCancelNotebookExecutions(notebookUri: URI): void { @@ -142,14 +143,68 @@ export class NotebookExecutionStateService extends Disposable implements INotebo return exe; } - private _setLastFailedCell(notebook: URI, cellHandle: number) { - this._lastFailedCells.set(notebook, cellHandle); - this._onDidChangeLastRunFailState.fire({ failed: true, notebook }); + private _setLastFailedCell(notebookURI: URI, cellHandle: number): void { + const prevLastFailedCellInfo = this._lastFailedCells.get(notebookURI); + const notebook = this._notebookService.getNotebookTextModel(notebookURI); + if (!notebook) { + return; + } + + const newLastFailedCellInfo: IFailedCellInfo = { + cellHandle: cellHandle, + disposable: prevLastFailedCellInfo ? prevLastFailedCellInfo.disposable : this._getFailedCellListener(notebook), + visible: true + }; + + this._lastFailedCells.set(notebookURI, newLastFailedCellInfo); + + this._onDidChangeLastRunFailState.fire({ visible: true, notebook: notebookURI }); } - private _clearLastFailedCell(notebook: URI) { - this._lastFailedCells.delete(notebook); - this._onDidChangeLastRunFailState.fire({ failed: false, notebook: notebook }); + private _setLastFailedCellVisibility(notebookURI: URI, visible: boolean): void { + const lastFailedCellInfo = this._lastFailedCells.get(notebookURI); + + if (lastFailedCellInfo) { + this._lastFailedCells.set(notebookURI, { + cellHandle: lastFailedCellInfo.cellHandle, + disposable: lastFailedCellInfo.disposable, + visible: visible, + }); + } + + this._onDidChangeLastRunFailState.fire({ visible: visible, notebook: notebookURI }); + } + + private _clearLastFailedCell(notebookURI: URI): void { + const lastFailedCellInfo = this._lastFailedCells.get(notebookURI); + + if (lastFailedCellInfo) { + lastFailedCellInfo.disposable?.dispose(); + this._lastFailedCells.delete(notebookURI); + } + + this._onDidChangeLastRunFailState.fire({ visible: false, notebook: notebookURI }); + } + + private _getFailedCellListener(notebook: NotebookTextModel): IDisposable { + return notebook.onWillAddRemoveCells((e: NotebookTextModelWillAddRemoveEvent) => { + const lastFailedCell = this._lastFailedCells.get(notebook.uri)?.cellHandle; + if (lastFailedCell !== undefined) { + const lastFailedCellPos = notebook.cells.findIndex(c => c.handle === lastFailedCell); + e.rawEvent.changes.forEach(([start, deleteCount, addedCells]) => { + if (deleteCount) { + if (lastFailedCellPos >= start && lastFailedCellPos < start + deleteCount) { + this._setLastFailedCellVisibility(notebook.uri, false); + } + } + + if (addedCells.some(cell => cell.handle === lastFailedCell)) { + this._setLastFailedCellVisibility(notebook.uri, true); + } + + }); + } + }); } override dispose(): void { @@ -162,6 +217,7 @@ export class NotebookExecutionStateService extends Disposable implements INotebo this._cellListeners.forEach(disposable => disposable.dispose()); this._notebookListeners.forEach(disposable => disposable.dispose()); + this._lastFailedCells.forEach(elem => elem.disposable.dispose()); } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts index 5f68d74056c..0b27d730a1d 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts @@ -76,14 +76,12 @@ export class CellFocusIndicator extends CellPart { override updateInternalLayoutNow(element: ICellViewModel): void { if (element.cellKind === CellKind.Markup) { - // markdown cell const indicatorPostion = this.notebookEditor.notebookOptions.computeIndicatorPosition(element.layoutInfo.totalHeight, (element as MarkupCellViewModel).layoutInfo.foldHintHeight, this.notebookEditor.textModel?.viewType); this.bottom.domNode.style.transform = `translateY(${indicatorPostion.bottomIndicatorTop}px)`; this.left.setHeight(indicatorPostion.verticalIndicatorHeight); this.right.setHeight(indicatorPostion.verticalIndicatorHeight); - this.codeFocusIndicator.setHeight(indicatorPostion.verticalIndicatorHeight); + this.codeFocusIndicator.setHeight(indicatorPostion.verticalIndicatorHeight - this.getIndicatorTopMargin() * 2); } else { - // code cell const cell = element as CodeCellViewModel; const layoutInfo = this.notebookEditor.notebookOptions.getLayoutConfiguration(); const bottomToolbarDimensions = this.notebookEditor.notebookOptions.computeBottomToolbarDimensions(this.notebookEditor.textModel?.viewType); @@ -99,13 +97,17 @@ export class CellFocusIndicator extends CellPart { } private updateFocusIndicatorsForTitleMenu(): void { + this.left.domNode.style.transform = `translateY(${this.getIndicatorTopMargin()}px)`; + this.right.domNode.style.transform = `translateY(${this.getIndicatorTopMargin()}px)`; + } + + private getIndicatorTopMargin() { const layoutInfo = this.notebookEditor.notebookOptions.getLayoutConfiguration(); + if (this.titleToolbar.hasActions) { - this.left.domNode.style.transform = `translateY(${layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin}px)`; - this.right.domNode.style.transform = `translateY(${layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin}px)`; + return layoutInfo.editorToolbarHeight + layoutInfo.cellTopMargin; } else { - this.left.domNode.style.transform = `translateY(${layoutInfo.cellTopMargin}px)`; - this.right.domNode.style.transform = `translateY(${layoutInfo.cellTopMargin}px)`; + return layoutInfo.cellTopMargin; } } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts index e06c5ff4df9..6adf3857c97 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts @@ -280,7 +280,7 @@ export class CodeCell extends Disposable { } if (options.outputClassName) { - this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [options.outputClassName], []); + this.notebookEditor.deltaCellContainerClassNames(this.viewCell.id, [options.outputClassName], []); } }); @@ -290,7 +290,7 @@ export class CodeCell extends Disposable { } if (options.outputClassName) { - this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [], [options.outputClassName]); + this.notebookEditor.deltaCellContainerClassNames(this.viewCell.id, [], [options.outputClassName]); } }); })); @@ -301,7 +301,7 @@ export class CodeCell extends Disposable { } if (options.outputClassName) { - this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [options.outputClassName], []); + this.notebookEditor.deltaCellContainerClassNames(this.viewCell.id, [options.outputClassName], []); } }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts similarity index 98% rename from src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts rename to src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts index ac666a052eb..0a9308588bf 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts @@ -29,7 +29,7 @@ import { MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browse import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -export class StatefulMarkdownCell extends Disposable { +export class MarkupCell extends Disposable { private editor: CodeEditorWidget | null = null; @@ -203,20 +203,20 @@ export class StatefulMarkdownCell extends Disposable { this._register(this.viewCell.onCellDecorationsChanged((e) => { e.added.forEach(options => { if (options.className) { - this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [options.className], []); + this.notebookEditor.deltaCellContainerClassNames(this.viewCell.id, [options.className], []); } }); e.removed.forEach(options => { if (options.className) { - this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [], [options.className]); + this.notebookEditor.deltaCellContainerClassNames(this.viewCell.id, [], [options.className]); } }); })); this.viewCell.getCellDecorations().forEach(options => { if (options.className) { - this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [options.className], []); + this.notebookEditor.deltaCellContainerClassNames(this.viewCell.id, [options.className], []); } }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index a82b4e723cf..8a741be7426 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -13,6 +13,7 @@ import { getExtensionForMimeType } from 'vs/base/common/mime'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { dirname, joinPath } from 'vs/base/common/resources'; +import { equals } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { TokenizationRegistry } from 'vs/editor/common/languages'; @@ -315,7 +316,7 @@ export class BackLayerWebView extends Disposable { filter: brightness(0) invert(1) } - #container > div.nb-symbolHighlight { + #container .markup > div.nb-symbolHighlight { background-color: var(--theme-notebook-symbol-highlight-background); } @@ -929,13 +930,6 @@ var requirejs = (function() { } private initializeWebViewState() { - const renderers = new Set(); - for (const inset of this.insetMapping.values()) { - if (inset.renderer) { - renderers.add(inset.renderer); - } - } - this._preloadsCache.clear(); if (this._currentKernel) { this._updatePreloadsFromKernel(this._currentKernel); @@ -945,9 +939,6 @@ var requirejs = (function() { this._sendMessageToWebview({ ...inset.cachedCreation, initiallyHidden: this.hiddenInsetMapping.has(output) }); } - const mdCells = [...this.markupPreviewMapping.values()]; - this.markupPreviewMapping.clear(); - this.initializeMarkup(mdCells); this._updateStyles(); this._updateOptions(); } @@ -1052,7 +1043,7 @@ var requirejs = (function() { } const sameContent = newContent.content === entry.content; - const sameMetadata = newContent.metadata === entry.metadata; + const sameMetadata = (equals(newContent.metadata, entry.metadata)); if (!sameContent || !sameMetadata || !entry.visible) { this._sendMessageToWebview({ type: 'showMarkupCell', @@ -1406,7 +1397,7 @@ var requirejs = (function() { } - deltaCellOutputContainerClassNames(cellId: string, added: string[], removed: string[]) { + deltaCellContainerClassNames(cellId: string, added: string[], removed: string[]) { this._sendMessageToWebview({ type: 'decorations', cellId, diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 8e3ab0b4640..5bbf9dd0be2 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -41,7 +41,7 @@ import { RunToolbar } from 'vs/workbench/contrib/notebook/browser/view/cellParts import { CollapsedCellInput } from 'vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellInput'; import { CollapsedCellOutput } from 'vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellOutput'; import { FoldedCellHint } from 'vs/workbench/contrib/notebook/browser/view/cellParts/foldedCellHint'; -import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/cellParts/markdownCell'; +import { MarkupCell } from 'vs/workbench/contrib/notebook/browser/view/cellParts/markupCell'; import { CodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; @@ -210,7 +210,7 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen return; } - templateData.elementDisposables.add(templateData.instantiationService.createInstance(StatefulMarkdownCell, this.notebookEditor, element, templateData, this.renderedEditors)); + templateData.elementDisposables.add(templateData.instantiationService.createInstance(MarkupCell, this.notebookEditor, element, templateData, this.renderedEditors)); } disposeTemplate(templateData: MarkdownCellRenderTemplate): void { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 16fec06c8ba..262188fa568 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1158,11 +1158,14 @@ async function webviewPreloads(ctx: PreloadContext) { focusFirstFocusableInCell(event.data.cellId); break; case 'decorations': { + console.log(event); let outputContainer = document.getElementById(event.data.cellId); + console.log(outputContainer); if (!outputContainer) { viewModel.ensureOutputCell(event.data.cellId, -100000, true); outputContainer = document.getElementById(event.data.cellId); } + console.log(outputContainer); outputContainer?.classList.add(...event.data.addedClassNames); outputContainer?.classList.remove(...event.data.removedClassNames); break; @@ -1668,6 +1671,7 @@ async function webviewPreloads(ctx: PreloadContext) { private _content: { readonly value: string; readonly version: number; readonly metadata: NotebookCellMetadata }; constructor(id: string, mime: string, content: string, top: number, metadata: NotebookCellMetadata) { + const self = this; this.id = id; this._content = { value: content, version: 0, metadata: metadata }; @@ -1679,8 +1683,8 @@ async function webviewPreloads(ctx: PreloadContext) { id, mime, - metadata: (): NotebookCellMetadata => { - return this._content.metadata; + get metadata(): NotebookCellMetadata { + return self._content.metadata; }, text: (): string => { diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.ts index d603fa80208..892e19b433f 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.ts @@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import * as UUID from 'vs/base/common/uuid'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { CellEditState, CellFindMatch, CellFoldingState, CellLayoutContext, CellLayoutState, EditorFoldingStateDelegate, ICellOutputViewModel, ICellViewModel, MarkdownCellLayoutChangeEvent, MarkdownCellLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFindMatch, CellFoldingState, CellLayoutContext, CellLayoutState, EditorFoldingStateDelegate, ICellOutputViewModel, ICellViewModel, MarkupCellLayoutChangeEvent, MarkupCellLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { CellKind, INotebookSearchOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -23,7 +23,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM readonly cellKind = CellKind.Markup; - private _layoutInfo: MarkdownCellLayoutInfo; + private _layoutInfo: MarkupCellLayoutInfo; private _renderedHtml?: string; @@ -58,7 +58,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM throw new Error('MarkdownCellViewModel.editorHeight is write only'); } - protected readonly _onDidChangeLayout = this._register(new Emitter()); + protected readonly _onDidChangeLayout = this._register(new Emitter()); readonly onDidChangeLayout = this._onDidChangeLayout.event; get foldingState() { @@ -185,7 +185,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM } } - layoutChange(state: MarkdownCellLayoutChangeEvent) { + layoutChange(state: MarkupCellLayoutChangeEvent) { // recompute const foldHintHeight = this._computeFoldHintHeight(); if (!this.isInputCollapsed) { diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts index 27384f830d4..d71b45a02fa 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys.ts @@ -137,7 +137,7 @@ export class NotebookEditorContextKeys { private _updateForLastRunFailState(e: INotebookFailStateChangedEvent): void { if (e.notebook === this._editor.textModel?.uri) { - this._lastCellFailed.set(e.failed); + this._lastCellFailed.set(e.visible); } } diff --git a/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts b/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts index d1fbe75907f..996364b1eb0 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -40,10 +41,16 @@ export interface ICellExecutionStateChangedEvent { affectsNotebook(notebook: URI): boolean; } export interface INotebookFailStateChangedEvent { - failed: boolean; + visible: boolean; notebook: URI; } +export interface IFailedCellInfo { + cellHandle: number; + disposable: IDisposable; + visible: boolean; +} + export const INotebookExecutionStateService = createDecorator('INotebookExecutionStateService'); export interface INotebookExecutionStateService { diff --git a/src/vs/workbench/contrib/notebook/test/browser/contrib/find.test.ts b/src/vs/workbench/contrib/notebook/test/browser/contrib/find.test.ts index 6b1282d9afb..50aeeb9f290 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/contrib/find.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/contrib/find.test.ts @@ -67,13 +67,13 @@ suite('Notebook Find', () => { state.change({ searchString: '1' }, true); await found; assert.strictEqual(model.findMatches.length, 2); - assert.strictEqual(model.currentMatch, -1); - model.find({ previous: false }); assert.strictEqual(model.currentMatch, 0); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 1); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 0); + model.find({ previous: false }); + assert.strictEqual(model.currentMatch, 1); assert.strictEqual(editor.textModel.length, 3); @@ -88,7 +88,7 @@ suite('Notebook Find', () => { await found2; assert.strictEqual(editor.textModel.length, 4); assert.strictEqual(model.findMatches.length, 3); - assert.strictEqual(model.currentMatch, 0); + assert.strictEqual(model.currentMatch, 1); }); }); @@ -114,13 +114,13 @@ suite('Notebook Find', () => { await found; // find matches is not necessarily find results assert.strictEqual(model.findMatches.length, 4); - assert.strictEqual(model.currentMatch, -1); - model.find({ previous: false }); assert.strictEqual(model.currentMatch, 0); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 1); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 2); + model.find({ previous: false }); + assert.strictEqual(model.currentMatch, 3); const found2 = new Promise(resolve => state.onFindReplaceStateChange(e => { if (e.matchesCount) { resolve(true); } @@ -131,15 +131,15 @@ suite('Notebook Find', () => { await found2; assert.strictEqual(model.findMatches.length, 3); - assert.strictEqual(model.currentMatch, 2); + assert.strictEqual(model.currentMatch, 0); model.find({ previous: true }); - assert.strictEqual(model.currentMatch, 1); - model.find({ previous: false }); - assert.strictEqual(model.currentMatch, 2); - model.find({ previous: false }); assert.strictEqual(model.currentMatch, 3); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 0); + model.find({ previous: false }); + assert.strictEqual(model.currentMatch, 1); + model.find({ previous: false }); + assert.strictEqual(model.currentMatch, 2); }); }); @@ -165,7 +165,7 @@ suite('Notebook Find', () => { await found; // find matches is not necessarily find results assert.strictEqual(model.findMatches.length, 4); - assert.strictEqual(model.currentMatch, -1); + assert.strictEqual(model.currentMatch, 0); model.find({ previous: true }); assert.strictEqual(model.currentMatch, 4); @@ -207,11 +207,11 @@ suite('Notebook Find', () => { await found; // find matches is not necessarily find results assert.strictEqual(model.findMatches.length, 4); - assert.strictEqual(model.currentMatch, -1); + assert.strictEqual(model.currentMatch, 0); model.find({ previous: false }); model.find({ previous: false }); model.find({ previous: false }); - assert.strictEqual(model.currentMatch, 2); + assert.strictEqual(model.currentMatch, 3); const found2 = new Promise(resolve => state.onFindReplaceStateChange(e => { if (e.matchesCount) { resolve(true); } })); @@ -243,13 +243,13 @@ suite('Notebook Find', () => { state.change({ searchString: '1' }, true); await found; assert.strictEqual(model.findMatches.length, 2); - assert.strictEqual(model.currentMatch, -1); - model.find({ previous: false }); assert.strictEqual(model.currentMatch, 0); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 1); model.find({ previous: false }); assert.strictEqual(model.currentMatch, 0); + model.find({ previous: false }); + assert.strictEqual(model.currentMatch, 1); assert.strictEqual(editor.textModel.length, 3); diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 0cd4dd22539..6ae277b797a 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -55,7 +55,8 @@ import { KeyedTaskIdentifier as KeyedTaskIdentifier, TaskDefinition, RuntimeType, USER_TASKS_GROUP_KEY, TaskSettingId, - TasksSchemaProperties + TasksSchemaProperties, + TaskEventKind } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskService, ITaskProvider, IProblemMatcherRunOptions, ICustomizationProperties, ITaskFilter, IWorkspaceFolderTaskResult, CustomExecutionSupportedContext, ShellExecutionSupportedContext, ProcessExecutionSupportedContext, TaskCommandsRegistered } from 'vs/workbench/contrib/tasks/common/taskService'; import { getTemplates as getTaskTemplates } from 'vs/workbench/contrib/tasks/common/taskTemplates'; @@ -86,6 +87,7 @@ import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from import { VirtualWorkspaceContext } from 'vs/workbench/common/contextkeys'; import { Schemas } from 'vs/base/common/network'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; +import { ILifecycleService, ShutdownReason, StartupKind } from 'vs/workbench/services/lifecycle/common/lifecycle'; const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history'; const PROBLEM_MATCHER_NEVER_CONFIG = 'task.problemMatchers.neverPrompt'; @@ -228,6 +230,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private _waitForSupportedExecutions: Promise; private _onDidRegisterSupportedExecutions: Emitter = new Emitter(); private _onDidChangeTaskSystemInfo: Emitter = new Emitter(); + private _willRestart: boolean = false; public onDidChangeTaskSystemInfo: Event = this._onDidChangeTaskSystemInfo.event; constructor( @@ -263,7 +266,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer @IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService, @IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService, @ILogService private readonly _logService: ILogService, - @IThemeService private readonly _themeService: IThemeService + @IThemeService private readonly _themeService: IThemeService, + @ILifecycleService private readonly _lifecycleService: ILifecycleService ) { super(); @@ -319,7 +323,17 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } return task._label; }); - + this._lifecycleService.onBeforeShutdown(e => { + this._willRestart = e.reason !== ShutdownReason.RELOAD; + }); + this._register(this.onDidStateChange(e => { + if (this._willRestart) { + const key = e.__task?.getRecentlyUsedKey(); + if (e.kind === TaskEventKind.Terminated && key) { + this.removePersistentTask(key); + } + } + })); this._waitForSupportedExecutions = new Promise(resolve => { once(this._onDidRegisterSupportedExecutions.event)(() => resolve()); }); @@ -348,10 +362,19 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private async _reconnectTasks(): Promise { const tasks = await this.getSavedTasks('persistent'); + if (!this._taskSystem) { + await this._getTaskSystem(); + } if (!tasks.length) { this._tasksReconnected = true; return; } + if (this._lifecycleService.startupKind !== StartupKind.ReloadedWindow) { + this._persistentTasks?.clear(); + this._storageService.remove(AbstractTaskService.PersistentTasks_Key, StorageScope.WORKSPACE); + await this._storageService.flush(); + return; + } for (const task of tasks) { if (ConfiguringTask.is(task)) { const resolved = await this.tryResolveTask(task); @@ -1015,6 +1038,13 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } + public removePersistentTask(key: string) { + if (this._getTasksFromStorage('persistent').has(key)) { + this._getTasksFromStorage('persistent').delete(key); + this._savePersistentTasks(); + } + } + private _setTaskLRUCacheLimit() { const quickOpenHistoryLimit = this._configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); if (this._recentlyUsedTasks) { @@ -1820,7 +1850,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } private async _handleExecuteResult(executeResult: ITaskExecuteResult, runSource?: TaskRunSource): Promise { - if (this._configurationService.getValue(TaskSettingId.Reconnection) === true) { + if (this._configurationService.getValue(TaskSettingId.Reconnection) === true && runSource !== TaskRunSource.Reconnect) { await this._setPersistentTask(executeResult.task); } if (runSource === TaskRunSource.User) { @@ -1851,7 +1881,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } this._setRecentlyUsedTask(executeResult.task); - this._setPersistentTask(executeResult.task); return executeResult.promise; } diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index f19a3df394f..dea390f00fd 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -210,7 +210,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { private _terminalCreationQueue: Promise = Promise.resolve(); private _hasReconnected: boolean = false; private readonly _onDidStateChange: Emitter; - private _reconnectTerminals: ITerminalInstance[] = []; + private _reconnectedTerminals: ITerminalInstance[] | undefined; get taskShellIntegrationStartSequence(): string { return this._configurationService.getValue(TaskSettingId.ShowDecorations) ? VSCodeSequence(VSCodeOscPt.PromptStart) + VSCodeSequence(VSCodeOscPt.Property, `${VSCodeOscProperty.Task}=True`) + VSCodeSequence(VSCodeOscPt.CommandStart) : ''; @@ -252,6 +252,9 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._onDidStateChange = new Emitter(); this._taskSystemInfoResolver = taskSystemInfoResolver; this._register(this._terminalStatusManager = new TaskTerminalStatus(taskService)); + // connection state changes before this is created sometimes + this._reconnectToTerminals(); + this._register(this._terminalService.onDidChangeConnectionState(() => this._reconnectToTerminals())); } public get onDidStateChange(): Event { @@ -266,15 +269,8 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._outputService.showChannel(this._outputChannelId, true); } - public reconnect(task: Task, resolver: ITaskResolver, trigger: string = Triggers.reconnect): ITaskExecuteResult | undefined { - this._reconnectTerminals = this._terminalService.getReconnectedTerminals(ReconnectionType) || []; - if (this._reconnectTerminals?.length === 0) { - return; - } - if (!this._hasReconnected && this._reconnectTerminals && this._reconnectTerminals.length > 0) { - this._reviveTerminals(); - } - return this.run(task, resolver, trigger); + public reconnect(task: Task, resolver: ITaskResolver): ITaskExecuteResult { + return this.run(task, resolver, Triggers.reconnect); } public run(task: Task, resolver: ITaskResolver, trigger: string = Triggers.command): ITaskExecuteResult { @@ -1278,11 +1274,14 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } private async _reconnectToTerminal(task: Task): Promise { - for (let i = 0; i < this._reconnectTerminals.length; i++) { - const terminal = this._reconnectTerminals[i]; + if (!this._reconnectedTerminals) { + return; + } + for (let i = 0; i < this._reconnectedTerminals.length; i++) { + const terminal = this._reconnectedTerminals[i]; const taskForTerminal = terminal.shellLaunchConfig.attachPersistentProcess?.reconnectionProperties?.data as IReconnectionTaskData; - if (taskForTerminal?.id && task.getRecentlyUsedKey() === taskForTerminal.lastTask) { - this._reconnectTerminals.splice(i, 1); + if (taskForTerminal.lastTask === task.getRecentlyUsedKey()) { + this._reconnectedTerminals.splice(i, 1); return terminal; } } @@ -1318,15 +1317,15 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return createdTerminal; } - private _reviveTerminals(): void { - if (Object.entries(this._terminals).length > 0) { + private _reconnectToTerminals(): void { + if (this._hasReconnected) { return; } - const terminals = this._terminalService.getReconnectedTerminals(ReconnectionType)?.filter(t => !t.isDisposed); - if (!terminals?.length) { + this._reconnectedTerminals = this._terminalService.getReconnectedTerminals(ReconnectionType)?.filter(t => !t.isDisposed); + if (!this._reconnectedTerminals?.length) { return; } - for (const terminal of terminals) { + for (const terminal of this._reconnectedTerminals) { const task = terminal.shellLaunchConfig.attachPersistentProcess?.reconnectionProperties?.data as IReconnectionTaskData; if (!task) { continue; @@ -1335,6 +1334,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { this._terminals[terminal.instanceId] = terminalData; terminal.onDisposed(() => this._deleteTaskAndTerminal(terminal, terminalData)); } + this._hasReconnected = true; } private _deleteTaskAndTerminal(terminal: ITerminalInstance, terminalData: ITerminalData): void { diff --git a/src/vs/workbench/contrib/tasks/common/taskSystem.ts b/src/vs/workbench/contrib/tasks/common/taskSystem.ts index cb4948c21fe..570252ef92c 100644 --- a/src/vs/workbench/contrib/tasks/common/taskSystem.ts +++ b/src/vs/workbench/contrib/tasks/common/taskSystem.ts @@ -102,8 +102,8 @@ export interface ITaskSystemInfoResolver { export interface ITaskSystem { onDidStateChange: Event; + reconnect(task: Task, resolver: ITaskResolver): ITaskExecuteResult; run(task: Task, resolver: ITaskResolver): ITaskExecuteResult; - reconnect(task: Task, resolver: ITaskResolver): ITaskExecuteResult | undefined; rerun(): ITaskExecuteResult | undefined; isActive(): Promise; isActiveSync(): boolean; diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index cfa357558d2..ef30f501a6f 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -18,6 +18,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; + export const USER_TASKS_GROUP_KEY = 'settings'; export const TASK_RUNNING_STATE = new RawContextKey('taskRunning', false, nls.localize('tasks.taskRunningContext', "Whether a task is currently running.")); @@ -1151,7 +1152,7 @@ export namespace TaskEvent { processId: undefined as number | undefined, exitCode: undefined as number | undefined, terminalId: undefined as number | undefined, - __task: task, + __task: task }; if (kind === TaskEventKind.Start) { result.terminalId = processIdOrExitCodeOrTerminalId; diff --git a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts b/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts index 050ef08efde..56a07f78c07 100644 --- a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts +++ b/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts @@ -87,7 +87,8 @@ export class TaskService extends AbstractTaskService { @IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService, @ILogService logService: ILogService, @IThemeService themeService: IThemeService, - @IInstantiationService instantiationService: IInstantiationService) { + @IInstantiationService instantiationService: IInstantiationService, + ) { super(configurationService, markerService, outputService, @@ -121,6 +122,7 @@ export class TaskService extends AbstractTaskService { workspaceTrustManagementService, logService, themeService, + lifecycleService ); this._register(lifecycleService.onBeforeShutdown(event => event.veto(this.beforeShutdown(), 'veto.tasks'))); } diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index a7b1e8acf36..fd5f65c9b9b 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -59,7 +59,7 @@ __vsc_update_cwd() { __vsc_command_output_start() { builtin printf "\033]633;C\007" - builtin printf "\033]633;E;$__vsc_current_command\007" + builtin printf "\033]633;E;%s\007" "$__vsc_current_command" } __vsc_continuation_start() { @@ -124,7 +124,14 @@ if [[ -n "${bash_preexec_imported:-}" ]]; then precmd_functions+=(__vsc_prompt_cmd) preexec_functions+=(__vsc_preexec_only) else - __vsc_dbg_trap="$(trap -p DEBUG | cut -d' ' -f3 | tr -d \')" + __vsc_dbg_trap="$(trap -p DEBUG)" + if [[ "$__vsc_db_trap" =~ .*\[\[.* ]]; then + #HACK - is there a better way to do this? + __vsc_dbg_trap=${__vsc_dbg_trap#'trap -- '*} + __vsc_dbg_trap=${__vsc_dbg_trap%'DEBUG'} + else + __vsc_dbg_trap="$(trap -p DEBUG | cut -d' ' -f3 | tr -d \')" + fi if [[ -z "$__vsc_dbg_trap" ]]; then __vsc_preexec_only() { if [ "$__vsc_in_command_execution" = "0" ]; then diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh index 7db2583a817..640d58f8725 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh @@ -50,7 +50,8 @@ __vsc_update_cwd() { __vsc_command_output_start() { builtin printf "\033]633;C\007" - builtin printf "\033]633;E;$__vsc_current_command\007" + # Send command line, escaping printf format chars % + builtin printf "\033]633;E;%s\007" "$__vsc_current_command" } __vsc_continuation_start() { @@ -125,3 +126,7 @@ __vsc_preexec() { } add-zsh-hook precmd __vsc_precmd add-zsh-hook preexec __vsc_preexec + +if [[ $options[login] = off ]]; then + ZDOTDIR=$USER_ZDOTDIR +fi diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 index 5d7d4436094..53767db552c 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 @@ -36,7 +36,11 @@ function Global:Prompt() { # Sanitize the command line to ensure it can get transferred to the terminal and can be parsed # correctly. This isn't entirely safe but good for most cases, it's important for the Pt parameter # to only be composed of _printable_ characters as per the spec. - $CommandLine = $LastHistoryEntry.CommandLine ?? "" + if ($LastHistoryEntry.CommandLine) { + $CommandLine = $LastHistoryEntry.CommandLine + } else { + $CommandLine = "" + } $Result += $CommandLine.Replace("`n", "").Replace(";", "") $Result += "`a" # Command finished exit code diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/commandNavigationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/commandNavigationAddon.ts index 7b4caa70342..cac6e1e9ac5 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/commandNavigationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/commandNavigationAddon.ts @@ -73,9 +73,13 @@ export class CommandNavigationAddon extends Disposable implements ICommandTracke // Clear the current marker so successive focus/selection actions are performed from the // bottom of the buffer this._currentMarker = Boundary.Bottom; + this._resetNavigationDecoration(); + this._selectionStart = null; + } + + private _resetNavigationDecoration() { this._navigationDecoration?.dispose(); this._navigationDecoration = undefined; - this._selectionStart = null; } scrollToPreviousCommand(scrollPosition: ScrollPosition = ScrollPosition.Middle, retainSelection: boolean = false): void { @@ -112,7 +116,7 @@ export class CommandNavigationAddon extends Disposable implements ICommandTracke if (markerIndex < 0) { this._currentMarker = Boundary.Top; this._terminal.scrollToTop(); - this.clearMarker(); + this._resetNavigationDecoration(); return; } @@ -154,7 +158,7 @@ export class CommandNavigationAddon extends Disposable implements ICommandTracke if (markerIndex >= this._getCommandMarkers().length) { this._currentMarker = Boundary.Bottom; this._terminal.scrollToBottom(); - this.clearMarker(); + this._resetNavigationDecoration(); return; } diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts index d61acd4c4a4..410cb5de5ae 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts @@ -163,7 +163,7 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke this._ptys.set(id, pty); return pty; } catch (e) { - this._logService.trace(`Couldn't attach to process ${e.message}`); + this._logService.warn(`Couldn't attach to process ${e.message}`); } return undefined; } @@ -173,7 +173,7 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke const newId = await this._localPtyService.getRevivedPtyNewId(id) ?? id; return await this.attachToProcess(newId); } catch (e) { - this._logService.trace(`Couldn't attach to process ${e.message}`); + this._logService.warn(`Couldn't attach to process ${e.message}`); } return undefined; } diff --git a/src/vs/workbench/contrib/testing/common/testService.ts b/src/vs/workbench/contrib/testing/common/testService.ts index 7c2450a2e94..f4a19c91d99 100644 --- a/src/vs/workbench/contrib/testing/common/testService.ts +++ b/src/vs/workbench/contrib/testing/common/testService.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { IObservableValue, MutableObservableValue } from 'vs/workbench/contrib/testing/common/observableValue'; -import { AbstractIncrementalTestCollection, IncrementalTestCollectionItem, InternalTestItem, ITestItemContext, ResolvedTestRunRequest, RunTestForControllerRequest, TestItemExpandState, TestRunProfileBitset, TestsDiff } from 'vs/workbench/contrib/testing/common/testTypes'; +import { AbstractIncrementalTestCollection, IncrementalTestCollectionItem, InternalTestItem, ITestItemContext, ResolvedTestRunRequest, RunTestForControllerRequest, RunTestForControllerResult, TestItemExpandState, TestRunProfileBitset, TestsDiff } from 'vs/workbench/contrib/testing/common/testTypes'; import { TestExclusions } from 'vs/workbench/contrib/testing/common/testExclusions'; import { TestId } from 'vs/workbench/contrib/testing/common/testId'; import { ITestResult } from 'vs/workbench/contrib/testing/common/testResult'; @@ -26,7 +26,7 @@ export interface IMainThreadTestController { refreshTests(token: CancellationToken): Promise; configureRunProfile(profileId: number): void; expandTest(id: string, levels: number): Promise; - runTests(request: RunTestForControllerRequest, token: CancellationToken): Promise; + runTests(request: RunTestForControllerRequest[], token: CancellationToken): Promise; } export type TestDiffListener = (diff: TestsDiff) => void; diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index efc2afbd0ca..3b107fabf85 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -28,6 +28,7 @@ import { AmbiguousRunTestsRequest, IMainThreadTestController, ITestService } fro import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; +import { isDefined } from 'vs/base/common/types'; export class TestService extends Disposable implements ITestService { declare readonly _serviceBrand: undefined; @@ -194,18 +195,22 @@ export class TestService extends Disposable implements ITestService { const cancelSource = new CancellationTokenSource(token); this.uiRunningTests.set(result.id, cancelSource); - const requests = req.targets.map( - group => this.testControllers.get(group.controllerId)?.runTests( - { + const byController = groupBy(req.targets, (a, b) => a.controllerId.localeCompare(b.controllerId)); + const requests = byController.map( + group => this.testControllers.get(group[0].controllerId)?.runTests( + group.map(controlReq => ({ runId: result.id, - excludeExtIds: req.exclude!.filter(t => !group.testIds.includes(t)), - profileId: group.profileId, - controllerId: group.controllerId, - testIds: group.testIds, - }, + excludeExtIds: req.exclude!.filter(t => !controlReq.testIds.includes(t)), + profileId: controlReq.profileId, + controllerId: controlReq.controllerId, + testIds: controlReq.testIds, + })), cancelSource.token, - ).catch(err => { - this.notificationService.error(localize('testError', 'An error occurred attempting to run tests: {0}', err.message)); + ).then(result => { + const errs = result.map(r => r.error).filter(isDefined); + if (errs.length) { + this.notificationService.error(localize('testError', 'An error occurred attempting to run tests: {0}', errs.join(' '))); + } }) ); await this.saveAllBeforeTest(req); diff --git a/src/vs/workbench/contrib/testing/common/testTypes.ts b/src/vs/workbench/contrib/testing/common/testTypes.ts index 4f9620cc4a8..e9b714fb36f 100644 --- a/src/vs/workbench/contrib/testing/common/testTypes.ts +++ b/src/vs/workbench/contrib/testing/common/testTypes.ts @@ -90,6 +90,10 @@ export interface RunTestForControllerRequest { testIds: string[]; } +export interface RunTestForControllerResult { + error?: string; +} + /** * Location with a fully-instantiated Range and URI. */ diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index 7834080ed70..8ff9cecf63b 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -205,13 +205,7 @@ export abstract class AbstractFileDialogService implements IFileDialogService { } protected addFileToRecentlyOpened(uri: URI): void { - - // add the picked file into the list of recently opened - // only if it is outside the currently opened workspace - - if (!this.contextService.isInsideWorkspace(uri)) { - this.workspacesService.addRecentlyOpened([{ fileUri: uri, label: this.labelService.getUriLabel(uri) }]); - } + this.workspacesService.addRecentlyOpened([{ fileUri: uri, label: this.labelService.getUriLabel(uri) }]); } protected async pickFolderAndOpenSimplified(schema: string, options: IPickAndOpenOptions): Promise { @@ -241,7 +235,13 @@ export abstract class AbstractFileDialogService implements IFileDialogService { } options.title = nls.localize('saveFileAs.title', 'Save As'); - return this.saveRemoteResource(options); + const uri = await this.saveRemoteResource(options); + + if (uri) { + this.addFileToRecentlyOpened(uri); + } + + return uri; } protected async showSaveDialogSimplified(schema: string, options: ISaveDialogOptions): Promise { diff --git a/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts index dbd0f777b07..36f7e3e76a1 100644 --- a/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts @@ -133,7 +133,11 @@ export class FileDialogService extends AbstractFileDialogService implements IFil } else { const result = await this.nativeHostService.showSaveDialog(this.toNativeSaveDialogOptions(options)); if (result && !result.canceled && result.filePath) { - return URI.file(result.filePath); + const uri = URI.file(result.filePath); + + this.addFileToRecentlyOpened(uri); + + return uri; } } return; diff --git a/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts index 320aab963d5..681b4a8498e 100644 --- a/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts @@ -20,6 +20,7 @@ interface IBundledExtension { extensionPath: string; packageJSON: IExtensionManifest; packageNLS?: any; + browserNlsMetadataPath?: string; readmePath?: string; changelogPath?: string; } @@ -66,11 +67,19 @@ export class BuiltinExtensionsScannerService implements IBuiltinExtensionsScanne this.builtinExtensionsPromises = bundledExtensions.map(async e => { const id = getGalleryExtensionId(e.packageJSON.publisher, e.packageJSON.name); + const browserNlsBundleUris: { [language: string]: URI } = {}; + if (e.browserNlsMetadataPath) { + if (this.nlsUrl) { + browserNlsBundleUris[Language.value()] = uriIdentityService.extUri.joinPath(this.nlsUrl, id, 'main'); + } + browserNlsBundleUris.en = uriIdentityService.extUri.resolvePath(builtinExtensionsServiceUrl!, e.browserNlsMetadataPath); + } return { identifier: { id }, location: uriIdentityService.extUri.joinPath(builtinExtensionsServiceUrl!, e.extensionPath), type: ExtensionType.System, isBuiltin: true, + browserNlsBundleUris, manifest: e.packageNLS ? await this.localizeManifest(id, e.packageJSON, e.packageNLS) : e.packageJSON, readmeUrl: e.readmePath ? uriIdentityService.extUri.joinPath(builtinExtensionsServiceUrl!, e.readmePath) : undefined, changelogUrl: e.changelogPath ? uriIdentityService.extUri.joinPath(builtinExtensionsServiceUrl!, e.changelogPath) : undefined, diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index 61275010652..ff2d2c58475 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -76,6 +76,7 @@ interface IWebExtension { // deprecated in favor of packageNLSUris & fallbackPackageNLSUri packageNLSUri?: URI; packageNLSUris?: Map; + bundleNLSUris?: Map; fallbackPackageNLSUri?: URI; metadata?: Metadata; } @@ -444,7 +445,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } async addExtension(location: URI, metadata: Metadata, profileLocation?: URI): Promise { - const webExtension = await this.toWebExtension(location, undefined, undefined, undefined, undefined, undefined, metadata); + const webExtension = await this.toWebExtension(location, undefined, undefined, undefined, undefined, undefined, undefined, metadata); return this.addWebExtension(webExtension, profileLocation); } @@ -546,7 +547,8 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } extensionLocation = galleryExtension.properties.targetPlatform === TargetPlatform.WEB ? extensionLocation.with({ query: `${extensionLocation.query ? `${extensionLocation.query}&` : ''}target=${galleryExtension.properties.targetPlatform}` }) : extensionLocation; const extensionResources = await this.listExtensionResources(extensionLocation); - const packageNLSResources = this.getNLSResourceMapFromResources(extensionResources); + const packageNLSResources = this.getPackageNLSResourceMapFromResources(extensionResources); + const bundleNLSResources = this.getBundleNLSResourceMapFromResources(extensionResources); // The fallback, in English, will fill in any gaps missing in the localized file. const fallbackPackageNLSResource = extensionResources.find(e => basename(e) === 'package.nls.json'); @@ -554,13 +556,14 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten extensionLocation, galleryExtension.identifier, packageNLSResources, + bundleNLSResources, fallbackPackageNLSResource ? URI.parse(fallbackPackageNLSResource) : null, galleryExtension.assets.readme ? URI.parse(galleryExtension.assets.readme.uri) : undefined, galleryExtension.assets.changelog ? URI.parse(galleryExtension.assets.changelog.uri) : undefined, metadata); } - private getNLSResourceMapFromResources(extensionResources: string[]): Map { + private getPackageNLSResourceMapFromResources(extensionResources: string[]): Map { const packageNLSResources = new Map(); extensionResources.forEach(e => { // Grab all package.nls.{language}.json files @@ -572,7 +575,22 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten return packageNLSResources; } - private async toWebExtension(extensionLocation: URI, identifier?: IExtensionIdentifier, packageNLSUris?: Map, fallbackPackageNLSUri?: URI | null, readmeUri?: URI, changelogUri?: URI, metadata?: Metadata): Promise { + private getBundleNLSResourceMapFromResources(extensionResources: string[]): Map { + const bundleNLSResources = new Map(); + extensionResources.forEach(e => { + // Grab all nls.bundle.{language}.json files + const regexResult = /nls\.bundle\.([\w-]+)\.json/.exec(basename(e)); + if (regexResult?.[1]) { + bundleNLSResources.set(regexResult[1], URI.parse(e)); + } + if (basename(e) === 'nls.metadata.json') { + bundleNLSResources.set('en', URI.parse(e)); + } + }); + return bundleNLSResources; + } + + private async toWebExtension(extensionLocation: URI, identifier?: IExtensionIdentifier, packageNLSUris?: Map, bundleNLSUris?: Map, fallbackPackageNLSUri?: URI | null, readmeUri?: URI, changelogUri?: URI, metadata?: Metadata): Promise { let packageJSONContent; try { packageJSONContent = await this.extensionResourceLoaderService.readExtensionResource(joinPath(extensionLocation, 'package.json')); @@ -598,6 +616,21 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } } + if (bundleNLSUris === undefined) { + const englishStringsUri = joinPath( + this.uriIdentityService.extUri.dirname(joinPath(extensionLocation, manifest.browser)), + 'nls.metadata.json' + ); + + try { + await this.extensionResourceLoaderService.readExtensionResource(englishStringsUri); + bundleNLSUris = new Map(); + bundleNLSUris.set('en', englishStringsUri); + } catch (error) { + // noop if file doesn't exist + } + } + return { identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: identifier?.uuid }, version: manifest.version, @@ -605,6 +638,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten readmeUri, changelogUri, packageNLSUris, + bundleNLSUris, fallbackPackageNLSUri: fallbackPackageNLSUri ? fallbackPackageNLSUri : undefined, metadata, }; @@ -661,12 +695,20 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } } + const browserNlsBundleUris: { [language: string]: URI } = {}; + if (webExtension.bundleNLSUris) { + for (const [language, uri] of webExtension.bundleNLSUris) { + browserNlsBundleUris[language] = uri; + } + } + return { identifier: { id: webExtension.identifier.id, uuid: webExtension.identifier.uuid || uuid }, location: webExtension.location, manifest, type, isBuiltin, + browserNlsBundleUris, readmeUrl: webExtension.readmeUri, changelogUrl: webExtension.changelogUri, metadata: webExtension.metadata, @@ -708,7 +750,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten if (!e.packageNLSUris && e.packageNLSUri) { e.fallbackPackageNLSUri = e.packageNLSUri; const extensionResources = await this.listExtensionResources(e.location); - e.packageNLSUris = this.getNLSResourceMapFromResources(extensionResources); + e.packageNLSUris = this.getPackageNLSResourceMapFromResources(extensionResources); e.packageNLSUri = undefined; } return e; diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 17d96c5614d..c3e783265a1 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -587,7 +587,8 @@ export function toExtensionDescription(extension: IExtension, isUnderDevelopment extensionLocation: extension.location, ...extension.manifest, uuid: extension.identifier.uuid, - targetPlatform: extension.targetPlatform + targetPlatform: extension.targetPlatform, + browserNlsBundleUris: extension.browserNlsBundleUris }; } diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 4135a251e94..e969fc50dce 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -143,9 +143,9 @@ export class LabelService extends Disposable implements ILabelService { this.os = OS; this.userHome = pathService.defaultUriScheme === Schemas.file ? this.pathService.userHome({ preferLocal: true }) : undefined; - const memento = this.storedFormattersMemento = new Memento('cachedResourceLabelFormatters', storageService); + const memento = this.storedFormattersMemento = new Memento('cachedResourceLabelFormatters2', storageService); this.storedFormatters = memento.getMemento(StorageScope.PROFILE, StorageTarget.MACHINE); - this.formatters = this.storedFormatters?.formatters || []; + this.formatters = this.storedFormatters?.formatters?.slice() || []; // Remote environment is potentially long running this.resolveRemoteEnvironment(); diff --git a/src/vs/workbench/services/label/test/browser/label.test.ts b/src/vs/workbench/services/label/test/browser/label.test.ts index 745055c930e..813df9e5585 100644 --- a/src/vs/workbench/services/label/test/browser/label.test.ts +++ b/src/vs/workbench/services/label/test/browser/label.test.ts @@ -166,7 +166,7 @@ suite('URI Label', () => { test('label caching', () => { - const m = new Memento('cachedResourceLabelFormatters', storageService).getMemento(StorageScope.PROFILE, StorageTarget.MACHINE); + const m = new Memento('cachedResourceLabelFormatters2', storageService).getMemento(StorageScope.PROFILE, StorageTarget.MACHINE); const makeFormatter = (scheme: string): ResourceLabelFormatter => ({ formatting: { label: `\${path} (${scheme})`, separator: '/' }, scheme }); assert.deepStrictEqual(m, {}); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 2c12f5a3305..d466a303e14 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -12,7 +12,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender'; import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryLevel, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { ITelemetryServiceConfig, TelemetryService as BaseTelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { isInternalTelemetry, ITelemetryAppender, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -38,6 +38,34 @@ export class TelemetryService extends Disposable implements ITelemetryService { super(); if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.ariaKey) { + this.impl = this.initializeService(environmentService, loggerService, configurationService, storageService, productService, remoteAgentService); + } else { + this.impl = NullTelemetryService; + } + + // When the level changes it could change from off to on and we want to make sure telemetry is properly intialized + this._register(configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(TELEMETRY_SETTING_ID)) { + this.impl = this.initializeService(environmentService, loggerService, configurationService, storageService, productService, remoteAgentService); + } + })); + } + + /** + * Initializes the telemetry service to be a full fledged service. + * This is only done once and only when telemetry is enabled as this will also ping the endpoint to + * ensure its not adblocked and we can send telemetry + */ + private initializeService( + environmentService: IBrowserWorkbenchEnvironmentService, + loggerService: ILoggerService, + configurationService: IConfigurationService, + storageService: IStorageService, + productService: IProductService, + remoteAgentService: IRemoteAgentService + ) { + const telemetrySupported = supportsTelemetry(productService, environmentService) && productService.aiConfig?.ariaKey; + if (telemetrySupported && this.impl === NullTelemetryService && this.telemetryLevel.value !== TelemetryLevel.NONE) { // If remote server is present send telemetry through that, else use the client side appender const appenders = []; const isInternal = isInternalTelemetry(productService, configurationService); @@ -50,10 +78,9 @@ export class TelemetryService extends Disposable implements ITelemetryService { sendErrorTelemetry: this.sendErrorTelemetry, }; - this.impl = this._register(new BaseTelemetryService(config, configurationService, productService)); - } else { - this.impl = NullTelemetryService; + return this._register(new BaseTelemetryService(config, configurationService, productService)); } + return NullTelemetryService; } setExperimentProperty(name: string, value: string): void { diff --git a/src/vs/workbench/services/userData/browser/userDataInit.ts b/src/vs/workbench/services/userData/browser/userDataInit.ts index 1d7504a2656..07ef427a949 100644 --- a/src/vs/workbench/services/userData/browser/userDataInit.ts +++ b/src/vs/workbench/services/userData/browser/userDataInit.ts @@ -16,7 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { IProductService } from 'vs/platform/product/common/productService'; import { IRequestService } from 'vs/platform/request/common/request'; -import { IRemoteUserData, IUserData, IUserDataInitializer, IUserDataSyncLogService, IUserDataSyncStoreClient, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { IRemoteUserData, IUserData, IUserDataInitializer, IUserDataSyncLogService, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; import { AuthenticationSessionInfo, getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; import { getSyncAreaLabel } from 'vs/workbench/services/userDataSync/common/userDataSync'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; @@ -77,10 +77,10 @@ export class UserDataInitializationService implements IUserDataInitializationSer }); } - private _userDataSyncStoreClientPromise: Promise | undefined; - private createUserDataSyncStoreClient(): Promise { + private _userDataSyncStoreClientPromise: Promise | undefined; + private createUserDataSyncStoreClient(): Promise { if (!this._userDataSyncStoreClientPromise) { - this._userDataSyncStoreClientPromise = (async (): Promise => { + this._userDataSyncStoreClientPromise = (async (): Promise => { try { if (!isWeb) { this.logService.trace(`Skipping initializing user data in desktop`); @@ -151,7 +151,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer userDataSyncStoreClient.setAuthToken(authenticationSession.accessToken, authenticationSession.providerId); // Cache global state data for global state initialization - this.globalStateUserData = await userDataSyncStoreClient.read(SyncResource.GlobalState, null); + this.globalStateUserData = await userDataSyncStoreClient.readResource(SyncResource.GlobalState, null); if (this.globalStateUserData) { const userDataSyncStoreType = new UserDataSyncStoreTypeSynchronizer(userDataSyncStoreClient, this.storageService, this.environmentService, this.fileService, this.logService).getSyncStoreType(this.globalStateUserData); @@ -238,7 +238,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer if (!userDataSyncStoreClient) { return null; } - const userData = await userDataSyncStoreClient.read(SyncResource.Extensions, null); + const userData = await userDataSyncStoreClient.readResource(SyncResource.Extensions, null); return instantiationService.createInstance(ExtensionsPreviewInitializer, userData); })(); } @@ -260,7 +260,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer this.initialized.push(syncResource); this.logService.trace(`Initializing ${getSyncAreaLabel(syncResource)}`); const initializer = this.createSyncResourceInitializer(syncResource); - const userData = await userDataSyncStoreClient.read(syncResource, syncResource === SyncResource.GlobalState ? this.globalStateUserData : null); + const userData = await userDataSyncStoreClient.readResource(syncResource, syncResource === SyncResource.GlobalState ? this.globalStateUserData : null); await initializer.initialize(userData); this.logService.info(`Initialized ${getSyncAreaLabel(syncResource)}`); } catch (error) { diff --git a/test/unit/coverage.js b/test/unit/coverage.js index 49b748e3bf1..ac0c1440f4a 100644 --- a/test/unit/coverage.js +++ b/test/unit/coverage.js @@ -28,7 +28,12 @@ exports.initialize = function (loaderConfig) { } catch (err) { // missing source map... } - return instrumenter.instrumentSync(contents, source, map); + try { + return instrumenter.instrumentSync(contents, source, map); + } catch (e) { + console.error(`Error instrumenting ${source}: ${e}`); + throw e; + } }; }; diff --git a/yarn.lock b/yarn.lock index 8e979f354bb..f53cbf6caf3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,14 @@ resolved "https://registry.yarnpkg.com/7zip/-/7zip-0.0.6.tgz#9cafb171af82329490353b4816f03347aa150a30" integrity sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA= +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@azure/abort-controller@^1.0.0": version "1.0.4" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.4.tgz#fd3c4d46c8ed67aace42498c8e2270960250eafd" @@ -102,80 +110,141 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== +"@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: - "@babel/highlight" "^7.8.3" + "@babel/highlight" "^7.18.6" -"@babel/core@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" - integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== +"@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/core@^7.12.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8" + integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" - "@babel/helpers" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.10" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.10" + "@babel/types" "^7.18.10" convert-source-map "^1.7.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" -"@babel/generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" - integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug== +"@babel/generator@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.10.tgz#794f328bfabdcbaf0ebf9bf91b5b57b61fa77a2a" + integrity sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.18.10" + "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" -"@babel/helper-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" - integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== +"@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== dependencies: - "@babel/types" "^7.8.3" + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== "@babel/helper-validator-identifier@^7.10.4": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== -"@babel/helpers@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85" - integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ== +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" "@babel/highlight@^7.10.4": version "7.10.4" @@ -186,51 +255,52 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" - integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== dependencies: + "@babel/helper-validator-identifier" "^7.18.6" chalk "^2.0.0" - esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.7.5", "@babel/parser@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" - integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== +"@babel/parser@^7.14.7", "@babel/parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.10.tgz#94b5f8522356e69e8277276adf67ed280c90ecc1" + integrity sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg== -"@babel/template@^7.7.4", "@babel/template@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" - integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== +"@babel/template@^7.18.10", "@babel/template@^7.18.6": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" -"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" - integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== +"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.10.tgz#37ad97d1cb00efa869b91dd5d1950f8a6cf0cb08" + integrity sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.13" -"@babel/types@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" - integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" + integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== dependencies: - esutils "^2.0.2" - lodash "^4.17.13" + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" "@discoveryjs/json-ext@^0.5.0": @@ -316,6 +386,46 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@koa/cors@^3.3.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.3.0.tgz#b4c1c7ee303b7c968c8727f2a638a74675b50bb2" @@ -2075,6 +2185,16 @@ browserslist@^4.0.0, browserslist@^4.14.5: escalade "^3.1.1" node-releases "^1.1.71" +browserslist@^4.20.2: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== + dependencies: + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" + buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -2290,6 +2410,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001219: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== +caniuse-lite@^1.0.30001370: + version "1.0.30001373" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz#2dc3bc3bfcb5d5a929bec11300883040d7b4b4be" + integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -3578,6 +3703,11 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.737.tgz#196f2e9656f4f3c31930750e1899c091b72d36b5" integrity sha512-P/B84AgUSQXaum7a8m11HUsYL8tj9h/Pt5f7Hg7Ty6bm5DxlFq+e5+ouHUoNQMsKDJ7u4yGfI8mOErCmSH9wyg== +electron-to-chromium@^1.4.202: + version "1.4.207" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.207.tgz#9c3310ebace2952903d05dcaba8abe3a4ed44c01" + integrity sha512-piH7MJDJp4rJCduWbVvmUd59AUne1AFBJ8JaRQvk0KzNTSUnZrVXHCZc+eg+CGE4OujkcLJznhGKD6tuAshj5Q== + electron@19.0.11: version "19.0.11" resolved "https://registry.yarnpkg.com/electron/-/electron-19.0.11.tgz#0c0a52abc08694fd38916d9270baf45bb7752a27" @@ -4674,10 +4804,10 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^1.0.1: version "1.0.3" @@ -6132,17 +6262,20 @@ istanbul-lib-coverage@^3.0.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== -istanbul-lib-instrument@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz#53321a7970f076262fd3292c8f9b2e4ac544aae1" - integrity sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ== +istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== dependencies: - "@babel/core" "^7.7.5" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" + istanbul-lib-coverage "^3.2.0" semver "^6.3.0" istanbul-lib-report@^3.0.0: @@ -6154,19 +6287,19 @@ istanbul-lib-report@^3.0.0: make-dir "^3.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== +istanbul-lib-source-maps@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.0.tgz#d4d16d035db99581b6194e119bbf36c963c5eb70" - integrity sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A== +istanbul-reports@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -6276,13 +6409,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" - integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== - dependencies: - minimist "^1.2.0" - json5@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" @@ -6290,6 +6416,11 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -6624,7 +6755,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7372,6 +7503,11 @@ node-releases@^1.1.71: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + node.extend@~1.1.2: version "1.1.8" resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" @@ -8982,13 +9118,6 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.4.0: is-core-module "^2.1.0" path-parse "^1.0.6" -resolve@^1.3.2: - version "1.14.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2" - integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ== - dependencies: - path-parse "^1.0.6" - resolve@^1.9.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" @@ -9481,7 +9610,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6: +source-map@^0.5.1, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -10559,6 +10688,14 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"