From ee3663c1cd11b15a96dee9c2f952af7cfbcfab3e Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Thu, 18 Jul 2019 18:32:57 -0700 Subject: [PATCH] Merge from vscode aba87f135229c17c4624341b7a2499dcedafcb87 (#6430) * Merge from vscode aba87f135229c17c4624341b7a2499dcedafcb87 * fix compile errors --- .../common/extract-telemetry.sh | 25 +- .../common/telemetry-config.json | 72 ++++ build/package.json | 1 + build/yarn.lock | 322 ++++++++++++++- extensions/git/package.json | 6 + .../client/src/jsonMain.ts | 22 +- .../server/src/jsonServerMain.ts | 3 +- .../markdown-language-features/package.json | 7 +- .../src/commands/showSource.ts | 8 +- .../src/features/preview.ts | 10 + .../src/features/previewManager.ts | 5 + extensions/xml/package.json | 2 + package.json | 12 +- remote/package.json | 4 +- remote/web/package.json | 3 +- remote/web/yarn.lock | 5 + remote/yarn.lock | 18 +- .../test/common/telemetryUtilities.test.ts | 4 +- .../modelComponents/webview.component.ts | 8 +- .../contents/webviewContent.component.ts | 6 +- .../webview/webviewWidget.component.ts | 6 +- .../browser/connectionViewletPanel.ts | 18 +- .../webview/electron-browser/webViewDialog.ts | 6 +- src/typings/semver-umd.d.ts | 10 + src/vs/base/common/platform.ts | 10 +- src/vs/base/node/cpuUsage.sh | 4 +- src/vs/base/parts/ipc/common/ipc.ts | 2 +- src/vs/code/browser/workbench/workbench.html | 5 +- src/vs/code/browser/workbench/workbench.js | 1 + .../issue/issueReporterMain.ts | 2 +- .../sharedProcess/sharedProcessMain.ts | 4 +- src/vs/code/electron-main/app.ts | 19 +- src/vs/code/electron-main/main.ts | 4 +- src/vs/code/electron-main/windows.ts | 3 +- src/vs/code/node/cliProcessMain.ts | 9 +- .../browser/viewParts/minimap/minimap.ts | 10 + src/vs/editor/common/model/textModel.ts | 4 + src/vs/editor/common/modes.ts | 5 +- .../editor/common/view/editorColorRegistry.ts | 4 +- src/vs/editor/common/viewModel/viewModel.ts | 1 + .../editor/common/viewModel/viewModelImpl.ts | 12 +- .../debug}/common/extensionHostDebug.ts | 0 .../debug/common/extensionHostDebugIpc.ts | 99 +++++ .../diagnostics/node/diagnosticsService.ts | 19 +- .../environment/common/environment.ts | 4 +- .../environment/node/environmentService.ts | 3 + .../common/extensionGalleryService.ts | 65 +-- .../common/extensionManagement.ts | 105 ----- .../extensionManagementIpc.ts | 0 .../node/extensionManagementService.ts | 4 +- .../launch/electron-main/launchService.ts | 3 +- .../platform/menubar/electron-main/menubar.ts | 3 +- .../product/browser/productService.ts | 4 +- src/vs/platform/product/common/product.ts | 4 + .../browser/workbenchCommonProperties.ts | 86 ++++ .../telemetry/common/telemetryUtils.ts | 73 ++++ .../telemetry/node/appInsightsAppender.ts | 76 +--- src/vs/platform/telemetry/node/telemetry.ts | 46 +-- src/vs/platform/theme/common/colorRegistry.ts | 4 +- .../electron-main/abstractUpdateService.ts | 4 + .../electron-main/updateService.darwin.ts | 20 +- .../electron-main/updateService.linux.ts | 19 +- .../electron-main/updateService.snap.ts | 17 +- .../electron-main/updateService.win32.ts | 9 +- src/vs/platform/windows/common/windows.ts | 1 + .../platform/windows/electron-main/windows.ts | 1 + .../windows/electron-main/windowsService.ts | 5 +- src/vs/vscode.proposed.d.ts | 48 --- .../api/browser/mainThreadCodeInsets.ts | 7 +- .../api/browser/mainThreadComments.ts | 4 - .../api/browser/mainThreadConsole.ts | 2 +- .../api/browser/mainThreadExtensionService.ts | 23 +- .../api/browser/mainThreadWebview.ts | 122 +++--- .../workbench/api/common/extHost.protocol.ts | 1 - .../workbench/api/common/extHostComments.ts | 55 +-- src/vs/workbench/api/node/extHostCLIServer.ts | 5 +- .../api/node/extHostRequireInterceptor.ts | 20 +- .../parts/statusbar/media/statusbarpart.css | 2 +- .../workbench/browser/web.simpleservices.ts | 174 +++----- .../contrib/comments/browser/commentNode.ts | 14 +- .../comments/browser/commentService.ts | 17 - .../comments/browser/commentThreadWidget.ts | 25 +- .../browser/commentsEditorContribution.ts | 8 +- .../contrib/comments/browser/commentsPanel.ts | 4 +- .../comments/browser/commentsTreeViewer.ts | 2 +- .../comments/browser/media/delete-dark.svg | 3 - .../comments/browser/media/delete-hc.svg | 3 - .../comments/browser/media/delete-light.svg | 3 - .../comments/browser/media/edit-dark.svg | 4 - .../comments/browser/media/edit-hc.svg | 4 - .../comments/browser/media/edit-light.svg | 4 - .../contrib/comments/browser/media/review.css | 38 +- .../contrib/debug/browser/debugService.ts | 2 +- .../electron-browser/experimentService.ts | 10 +- .../experimentService.test.ts | 4 +- .../extensions/browser/extensionEditor.ts | 46 ++- .../browser/extensions.contribution.ts | 373 ++++++++++++++++++ .../extensions/browser/extensionsActions.ts | 144 +++---- .../extensions/browser/extensionsList.ts | 2 +- .../extensions/browser/extensionsViewlet.ts | 16 +- .../extensions/browser/extensionsViews.ts | 3 +- .../extensions/browser/extensionsWidgets.ts | 23 +- .../extensionsWorkbenchService.ts | 94 +++-- .../contrib/extensions/common/extensions.ts | 6 +- .../extensions/common/extensionsUtils.ts | 5 +- .../electron-browser/extensionTipsService.ts | 6 +- .../extensions.contribution.ts | 340 +--------------- .../runtimeExtensionsEditor.ts | 6 +- .../extensionsActions.test.ts | 65 +-- .../extensionsTipsService.test.ts | 3 +- .../electron-browser/extensionsViews.test.ts | 16 +- .../extensionsWorkbenchService.test.ts | 251 ++++++------ .../format/browser/formatActionsMultiple.ts | 2 +- .../issue/electron-browser/issueService.ts | 3 +- .../preferences/browser/preferencesSearch.ts | 3 +- .../preferences/browser/settingsTree.ts | 4 + .../tasks/browser/abstractTaskService.ts | 18 +- .../tasks/electron-browser/taskService.ts | 2 +- .../browser/telemetry.contribution.ts | 58 +-- .../electron-browser/releaseNotesEditor.ts | 24 +- .../contrib/update/electron-browser/update.ts | 2 +- .../contrib/webview/browser/webviewEditor.ts | 230 ++++------- .../webview/browser/webviewEditorInput.ts | 198 +--------- .../browser/webviewEditorInputFactory.ts | 27 +- .../webview/browser/webviewEditorService.ts | 66 +++- .../contrib/webview/browser/webviewElement.ts | 2 +- .../contrib/webview/browser/webviewService.ts | 187 ++++++++- .../contrib/webview/common/webview.ts | 30 +- .../electron-browser/webviewCommands.ts | 6 +- .../electron-browser/webviewElement.ts | 26 +- .../electron-browser/webviewService.ts | 19 +- .../electron-browser/telemetryOptOut.ts | 14 +- .../welcome/page/browser/welcomePage.ts | 12 +- .../walkThrough/browser/walkThroughPart.ts | 38 +- src/vs/workbench/electron-browser/window.ts | 12 +- .../environment/browser/environmentService.ts | 33 +- .../extensionEnablementService.ts | 49 ++- .../common/extensionManagement.ts | 117 ++++++ .../extensionManagementServerService.ts | 45 +++ .../common/extensionManagementService.ts} | 95 ++--- .../extensionManagementServerService.ts | 15 +- .../node/extensionManagementService.ts | 36 ++ .../extensionEnablementService.test.ts | 335 ++++++++++------ .../extensions/browser/extensionService.ts | 2 +- .../common/abstractExtensionService.ts | 2 +- .../common/inactiveExtensionUrlHandler.ts | 5 +- .../common/remoteExtensionHostClient.ts | 2 +- .../cachedExtensionScanner.ts | 2 +- .../electron-browser/extensionHost.ts | 2 +- .../extensionHostDebugService.ts | 123 +----- .../electron-browser/extensionService.ts | 3 +- .../remoteExtensionManagementIpc.ts | 2 +- .../extensions/node/extensionPoints.ts | 2 +- .../telemetry/browser/telemetryService.ts | 170 ++++++++ .../electron-browser/telemetryService.ts | 2 +- src/vs/workbench/workbench.main.ts | 11 +- src/vs/workbench/workbench.web.main.ts | 19 +- yarn.lock | 44 +-- 158 files changed, 3101 insertions(+), 2361 deletions(-) create mode 100644 build/azure-pipelines/common/telemetry-config.json create mode 100644 src/typings/semver-umd.d.ts rename src/vs/{workbench/services/extensions => platform/debug}/common/extensionHostDebug.ts (100%) create mode 100644 src/vs/platform/debug/common/extensionHostDebugIpc.ts rename src/vs/platform/extensionManagement/{node => common}/extensionManagementIpc.ts (100%) create mode 100644 src/vs/platform/telemetry/browser/workbenchCommonProperties.ts delete mode 100644 src/vs/workbench/contrib/comments/browser/media/delete-dark.svg delete mode 100644 src/vs/workbench/contrib/comments/browser/media/delete-hc.svg delete mode 100644 src/vs/workbench/contrib/comments/browser/media/delete-light.svg delete mode 100644 src/vs/workbench/contrib/comments/browser/media/edit-dark.svg delete mode 100644 src/vs/workbench/contrib/comments/browser/media/edit-hc.svg delete mode 100644 src/vs/workbench/contrib/comments/browser/media/edit-light.svg create mode 100644 src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts rename src/vs/workbench/contrib/extensions/{node => browser}/extensionsWorkbenchService.ts (93%) rename src/vs/workbench/services/extensionManagement/{node => common}/extensionEnablementService.ts (89%) create mode 100644 src/vs/workbench/services/extensionManagement/common/extensionManagement.ts create mode 100644 src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts rename src/vs/workbench/services/{extensions/node/multiExtensionManagement.ts => extensionManagement/common/extensionManagementService.ts} (70%) rename src/vs/workbench/services/{extensions => extensionManagement}/electron-browser/extensionManagementServerService.ts (80%) create mode 100644 src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts create mode 100644 src/vs/workbench/services/telemetry/browser/telemetryService.ts diff --git a/build/azure-pipelines/common/extract-telemetry.sh b/build/azure-pipelines/common/extract-telemetry.sh index 916c87c82c..84bbd9c537 100755 --- a/build/azure-pipelines/common/extract-telemetry.sh +++ b/build/azure-pipelines/common/extract-telemetry.sh @@ -2,29 +2,18 @@ set -e cd $BUILD_STAGINGDIRECTORY -git clone https://github.com/microsoft/vscode-telemetry-extractor.git -cd vscode-telemetry-extractor -git checkout 4e64f3de30f8fccb58ebdc0d85c4861a135d46cf -npm i -npm run compile -cd src -mkdir telemetry-sources -cd telemetry-sources +mkdir extraction +cd extraction git clone --depth 1 https://github.com/Microsoft/vscode-extension-telemetry.git git clone --depth 1 https://github.com/Microsoft/vscode-chrome-debug-core.git -git clone --depth 1 https://github.com/Microsoft/vscode-chrome-debug.git git clone --depth 1 https://github.com/Microsoft/vscode-node-debug2.git git clone --depth 1 https://github.com/Microsoft/vscode-node-debug.git -git clone --depth 1 https://github.com/Microsoft/vscode-docker.git -git clone --depth 1 https://github.com/Microsoft/vscode-go.git -git clone --depth 1 https://github.com/Microsoft/vscode-azure-account.git git clone --depth 1 https://github.com/Microsoft/vscode-html-languageservice.git git clone --depth 1 https://github.com/Microsoft/vscode-json-languageservice.git -git clone --depth 1 https://github.com/Microsoft/vscode-mono-debug.git -git clone --depth 1 https://github.com/Microsoft/TypeScript.git -cd ../../ -node ./out/cli-extract.js --sourceDir $BUILD_SOURCESDIRECTORY --excludedDirPattern extensions --outputDir . --applyEndpoints --includeIsMeasurement -node ./out/cli-extract-extensions.js --sourceDir ./src/telemetry-sources --outputDir . --applyEndpoints --includeIsMeasurement +$BUILD_SOURCESDIRECTORY/build/node_modules/.bin/vscode-telemetry-extractor --sourceDir $BUILD_SOURCESDIRECTORY --excludedDir $BUILD_SOURCESDIRECTORY/extensions --outputDir . --applyEndpoints +$BUILD_SOURCESDIRECTORY/build/node_modules/.bin/vscode-telemetry-extractor --config $BUILD_SOURCESDIRECTORY/build/azure-pipelines/common/telemetry-config.json -o . mkdir -p $BUILD_SOURCESDIRECTORY/.build/telemetry mv declarations-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-core.json -mv declarations-extensions-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-extensions.json \ No newline at end of file +mv config-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-extensions.json +cd .. +rm -rf extraction \ No newline at end of file diff --git a/build/azure-pipelines/common/telemetry-config.json b/build/azure-pipelines/common/telemetry-config.json new file mode 100644 index 0000000000..fcba1e042b --- /dev/null +++ b/build/azure-pipelines/common/telemetry-config.json @@ -0,0 +1,72 @@ +[ + { + "eventPrefix": "typescript-language-features/", + "sourceDirs": [ + "../../s/extensions/typescript-language-features" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "git/", + "sourceDirs": [ + "../../s/extensions/git" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "extension-telemetry/", + "sourceDirs": [ + "vscode-extension-telemetry" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "vscode-markdown/", + "sourceDirs": [ + "../../s/extensions/markdown-language-features" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "html-language-features/", + "sourceDirs": [ + "../../s/extensions/html-language-features", + "vscode-html-languageservice" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "json-language-features/", + "sourceDirs": [ + "../../s/extensions/json-language-features", + "vscode-json-languageservice" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "ms-vscode.node2/", + "sourceDirs": [ + "vscode-chrome-debug-core", + "vscode-node-debug2" + ], + "excludedDirs": [], + "applyEndpoints": true, + "patchDebugEvents": true + }, + { + "eventPrefix": "ms-vscode.node/", + "sourceDirs": [ + "vscode-chrome-debug-core", + "vscode-node-debug" + ], + "excludedDirs": [], + "applyEndpoints": true, + "patchDebugEvents": true + } +] \ No newline at end of file diff --git a/build/package.json b/build/package.json index 535a99c2e8..4fb67a9474 100644 --- a/build/package.json +++ b/build/package.json @@ -44,6 +44,7 @@ "service-downloader": "github:anthonydresser/service-downloader#0.1.5", "typescript": "3.5.2", "vsce": "1.48.0", + "vscode-telemetry-extractor": "1.4.3", "xml2js": "^0.4.17" }, "scripts": { diff --git a/build/yarn.lock b/build/yarn.lock index 273527824c..b33452a884 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@dsherret/to-absolute-glob@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1f6475dc8bd974cea07a2daf3864b317b1dd332c" + integrity sha1-H2R13IvZdM6gei2vOGSzF7HdMyw= + dependencies: + is-absolute "^1.0.0" + is-negated-glob "^1.0.0" + "@gulp-sourcemaps/map-sources@1.X": version "1.0.0" resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda" @@ -10,6 +18,27 @@ normalize-path "^2.0.1" through2 "^2.0.3" +"@nodelib/fs.scandir@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz#7fa8fed654939e1a39753d286b48b4836d00e0eb" + integrity sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg== + dependencies: + "@nodelib/fs.stat" "2.0.1" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.1", "@nodelib/fs.stat@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz#814f71b1167390cfcb6a6b3d9cdeb0951a192c14" + integrity sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw== + +"@nodelib/fs.walk@^1.2.1": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz#6a6450c5e17012abd81450eb74949a4d970d2807" + integrity sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ== + dependencies: + "@nodelib/fs.scandir" "2.1.1" + fastq "^1.6.0" + "@types/ansi-colors@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@types/ansi-colors/-/ansi-colors-3.2.0.tgz#3e4fe85d9131ce1c6994f3040bd0b25306c16a6e" @@ -389,11 +418,21 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-back@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + array-differ@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -401,6 +440,11 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.1, array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -411,6 +455,11 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" @@ -595,6 +644,13 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + browserify-mime@~1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/browserify-mime/-/browserify-mime-1.2.9.tgz#aeb1af28de6c0d7a6a2ce40adb68ff18422af31f" @@ -737,6 +793,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +code-block-writer@9.4.1: + version "9.4.1" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-9.4.1.tgz#1448fca79dfc7a3649000f4c85be6bc770604c4c" + integrity sha512-LHAB+DL4YZDcwK8y/kAxZ0Lf/ncwLh/Ux4cTVWbPwIdrf1gPxXiPcwpz8r8/KqXu1aD+Raz46EOxDjFlbyO6bA== + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -786,6 +847,16 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" +command-line-args@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a" + integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg== + dependencies: + array-back "^3.0.1" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + commander@^2.12.1, commander@^2.8.1: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -1050,6 +1121,13 @@ diff@^3.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + documentdb@1.13.0: version "1.13.0" resolved "https://registry.yarnpkg.com/documentdb/-/documentdb-1.13.0.tgz#bba6f03150b2f42498cec4261bc439d834a33f8b" @@ -1235,11 +1313,30 @@ fast-deep-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= +fast-glob@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" + integrity sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg== + dependencies: + "@nodelib/fs.stat" "^2.0.1" + "@nodelib/fs.walk" "^1.2.1" + glob-parent "^5.0.0" + is-glob "^4.0.1" + merge2 "^1.2.3" + micromatch "^4.0.2" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= +fastq@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2" + integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA== + dependencies: + reusify "^1.0.0" + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -1272,6 +1369,20 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -1312,6 +1423,15 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -1384,7 +1504,14 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3: +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + +glob@^7.0.3, glob@^7.0.6, glob@^7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -1396,6 +1523,32 @@ glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globby@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22" + integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -1424,6 +1577,11 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -1676,6 +1834,11 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" +ignore@^5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.2.tgz#e28e584d43ad7e92f96995019cc43b9e1ac49558" + integrity sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1694,6 +1857,14 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -1795,11 +1966,23 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-natural-number@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= +is-negated-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" + integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -1807,6 +1990,11 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -1833,6 +2021,13 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -1843,12 +2038,19 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-windows@^1.0.2: +is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== @@ -1927,6 +2129,13 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -2028,6 +2237,11 @@ lodash._root@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + lodash.escape@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" @@ -2130,6 +2344,11 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= +merge2@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" + integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== + micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -2149,6 +2368,14 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -2240,6 +2467,17 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +multimatch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" + integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + multipipe@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" @@ -2474,6 +2712,11 @@ path-parse@^1.0.5: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -2489,6 +2732,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picomatch@^2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" + integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2730,6 +2978,11 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +reusify@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@^2.2.8, rimraf@^2.6.1: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -2737,6 +2990,11 @@ rimraf@^2.2.8, rimraf@^2.6.1: dependencies: glob "^7.1.3" +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + safe-buffer@^5.0.1, safe-buffer@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -2827,6 +3085,11 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -3094,6 +3357,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -3118,6 +3388,20 @@ tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +ts-morph@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-3.1.3.tgz#bbfa1d14481ee23bdd1c030340ccf4a243cfc844" + integrity sha512-CwjgyJTtd3f8vBi7Vr0IOgdOY6Wi/Tq0MhieXOE2B5ns5WWRD7BwMNHtv+ZufKI/S2U/lMrh+Q3bOauE4tsv2g== + dependencies: + "@dsherret/to-absolute-glob" "^2.0.2" + code-block-writer "9.4.1" + fs-extra "^8.1.0" + glob-parent "^5.0.0" + globby "^10.0.1" + is-negated-glob "^1.0.0" + multimatch "^4.0.0" + typescript "^3.0.1" + tslib@^1.8.0, tslib@^1.8.1: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -3178,6 +3462,16 @@ typescript@3.5.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== +typescript@^3.0.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" @@ -3191,6 +3485,11 @@ unbzip2-stream@^1.0.9: buffer "^5.2.1" through "^2.3.8" +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= + underscore@1.8.3, underscore@~1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" @@ -3211,6 +3510,11 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -3309,6 +3613,20 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" +vscode-ripgrep@^1.4.0: + version "1.5.4" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.4.tgz#dae1c3eef350513299341cdf96e622c00b548eff" + integrity sha512-Bs8SvFAkR0QHf09J46VgNo19yRikOtj/f0zHzK3AM3ICjCGNN/BNoG9of6zGVHUTO+6Mk1RbKglyOHLKr8D1lg== + +vscode-telemetry-extractor@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.4.3.tgz#e4af380beb4e2a63d6e4fa819b25ba7ef6dc4a10" + integrity sha512-OFklPErZnUBjrKte3hg+irQXue5rzgz4qnvE8kdaOnW1E/wynHUEXW9t5vF5q0hu2lodpGMkybwLkSjONZVzvg== + dependencies: + command-line-args "^5.1.1" + ts-morph "^3.1.2" + vscode-ripgrep "^1.4.0" + vso-node-api@6.1.2-preview: version "6.1.2-preview" resolved "https://registry.yarnpkg.com/vso-node-api/-/vso-node-api-6.1.2-preview.tgz#aab3546df2451ecd894e071bb99b5df19c5fa78f" diff --git a/extensions/git/package.json b/extensions/git/package.json index 814f53020a..4a789aaa6a 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1246,12 +1246,18 @@ }, "git.ignoredRepositories": { "type": "array", + "items": { + "type": "string" + }, "default": [], "scope": "window", "description": "%config.ignoredRepositories%" }, "git.scanRepositories": { "type": "array", + "items": { + "type": "string" + }, "default": [], "scope": "resource", "description": "%config.scanRepositories%" diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index 7514379bc5..a4821627cb 100644 --- a/extensions/json-language-features/client/src/jsonMain.ts +++ b/extensions/json-language-features/client/src/jsonMain.ts @@ -10,7 +10,7 @@ import { xhr, XHRResponse, getErrorStatusDescription } from 'request-light'; const localize = nls.loadMessageBundle(); -import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor, TextDocument, Position, SelectionRange } from 'vscode'; +import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor } from 'vscode'; import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; @@ -216,26 +216,6 @@ export function activate(context: ExtensionContext) { extensions.onDidChange(_ => { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); }); - - documentSelector.forEach(selector => { - toDispose.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { - const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); - if (Array.isArray(rawResult)) { - return rawResult.map(rawSelectionRanges => { - return rawSelectionRanges.reduceRight((parent: SelectionRange | undefined, selectionRange: SelectionRange) => { - return { - range: client.protocol2CodeConverter.asRange(selectionRange.range), - parent, - }; - }, undefined)!; - }); - } - return []; - } - })); - }); }); diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index b5e74af2a9..54f24e1986 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -433,7 +433,8 @@ connection.onFoldingRanges((params, token) => { }, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token); }); -connection.onRequest('$/textDocument/selectionRanges', async (params, token) => { + +connection.onSelectionRanges((params, token) => { return runSafe(() => { const document = documents.get(params.textDocument.uri); if (document) { diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 84fdbd24b4..5e83c38bd2 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -4,8 +4,8 @@ "description": "%description%", "version": "1.0.0", "icon": "icon.png", - "publisher": "vscode", - "enableProposedApi": true, + "publisher": "vscode", + "enableProposedApi": true, "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { @@ -197,6 +197,9 @@ "properties": { "markdown.styles": { "type": "array", + "items": { + "type": "string" + }, "default": [], "description": "%markdown.styles.dec%", "scope": "resource" diff --git a/extensions/markdown-language-features/src/commands/showSource.ts b/extensions/markdown-language-features/src/commands/showSource.ts index bc562c9070..18c4755efe 100644 --- a/extensions/markdown-language-features/src/commands/showSource.ts +++ b/extensions/markdown-language-features/src/commands/showSource.ts @@ -15,9 +15,11 @@ export class ShowSourceCommand implements Command { ) { } public execute() { - if (this.previewManager.activePreviewResource) { - return vscode.workspace.openTextDocument(this.previewManager.activePreviewResource) - .then(document => vscode.window.showTextDocument(document)); + const { activePreviewResource, activePreviewResourceColumn } = this.previewManager; + if (activePreviewResource && activePreviewResourceColumn) { + return vscode.workspace.openTextDocument(activePreviewResource).then(document => { + vscode.window.showTextDocument(document, activePreviewResourceColumn); + }); } return undefined; } diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index 748686ef2a..8dd5ce8485 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -102,11 +102,13 @@ export class MarkdownPreview extends Disposable { const resource = vscode.Uri.parse(state.resource); const locked = state.locked; const line = state.line; + const resourceColumn = state.resourceColumn; const preview = new MarkdownPreview( webview, resource, locked, + resourceColumn, contentProvider, previewConfigurations, logger, @@ -125,6 +127,7 @@ export class MarkdownPreview extends Disposable { public static create( resource: vscode.Uri, previewColumn: vscode.ViewColumn, + resourceColumn: vscode.ViewColumn, locked: boolean, contentProvider: MarkdownContentProvider, previewConfigurations: MarkdownPreviewConfigurationManager, @@ -144,6 +147,7 @@ export class MarkdownPreview extends Disposable { webview, resource, locked, + resourceColumn, contentProvider, previewConfigurations, logger, @@ -155,6 +159,7 @@ export class MarkdownPreview extends Disposable { webview: vscode.WebviewPanel, resource: vscode.Uri, locked: boolean, + private readonly _resourceColumn: vscode.ViewColumn, private readonly _contentProvider: MarkdownContentProvider, private readonly _previewConfigurations: MarkdownPreviewConfigurationManager, private readonly _logger: Logger, @@ -249,11 +254,16 @@ export class MarkdownPreview extends Disposable { return this._resource; } + public get resourceColumn(): vscode.ViewColumn { + return this._resourceColumn; + } + public get state() { return { resource: this.resource.toString(), locked: this._locked, line: this.line, + resourceColumn: this.resourceColumn, imageInfo: this.imageInfo }; } diff --git a/extensions/markdown-language-features/src/features/previewManager.ts b/extensions/markdown-language-features/src/features/previewManager.ts index 2e076f15d3..787d65510f 100644 --- a/extensions/markdown-language-features/src/features/previewManager.ts +++ b/extensions/markdown-language-features/src/features/previewManager.ts @@ -65,6 +65,10 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview return this._activePreview && this._activePreview.resource; } + public get activePreviewResourceColumn() { + return this._activePreview && this._activePreview.resourceColumn; + } + public toggleLock() { const preview = this._activePreview; if (preview) { @@ -110,6 +114,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview const preview = MarkdownPreview.create( resource, previewSettings.previewColumn, + previewSettings.resourceColumn, previewSettings.locked, this._contentProvider, this._previewConfigurations, diff --git a/extensions/xml/package.json b/extensions/xml/package.json index 2e6cc49fd6..d76a632b10 100644 --- a/extensions/xml/package.json +++ b/extensions/xml/package.json @@ -23,6 +23,8 @@ ".dita", ".ditamap", ".dtd", + ".ent", + ".mod", ".dtml", ".fsproj", ".fxml", diff --git a/package.json b/package.json index 97c62b8f09..57acd2a2eb 100644 --- a/package.json +++ b/package.json @@ -66,14 +66,14 @@ "reflect-metadata": "^0.1.8", "rxjs": "5.4.0", "sanitize-html": "^1.19.1", - "semver": "^5.5.0", + "semver-umd": "^5.5.3", "slickgrid": "github:anthonydresser/SlickGrid#2.3.29", "spdlog": "^0.9.0", "sudo-prompt": "9.0.0", "v8-inspect-profiler": "^0.0.20", "vscode-chokidar": "2.1.7", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.3.1", + "vscode-ripgrep": "^1.5.4", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", "xterm": "3.15.0-beta71", @@ -113,7 +113,7 @@ "fast-plist": "0.1.2", "glob": "^5.0.13", "gulp": "^4.0.0", - "gulp-atom-electron": "^1.20.0", + "gulp-atom-electron": "^1.21.1", "gulp-azure-storage": "^0.10.0", "gulp-buffer": "0.0.2", "gulp-concat": "^2.6.1", @@ -188,8 +188,8 @@ "optionalDependencies": { "vscode-windows-ca-certs": "0.1.0", "vscode-windows-registry": "1.0.1", - "windows-foreground-love": "0.1.0", - "windows-mutex": "0.2.1", + "windows-foreground-love": "0.2.0", + "windows-mutex": "0.3.0", "windows-process-tree": "0.2.4" } -} +} \ No newline at end of file diff --git a/remote/package.json b/remote/package.json index 6fc6471a2c..a4113e1e74 100644 --- a/remote/package.json +++ b/remote/package.json @@ -14,11 +14,11 @@ "node-pty": "0.9.0-beta19", "nsfw": "1.2.5", "onigasm-umd": "^2.2.2", - "semver": "^5.5.0", + "semver-umd": "^5.5.3", "spdlog": "^0.9.0", "vscode-chokidar": "2.1.7", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.3.1", + "vscode-ripgrep": "^1.5.4", "vscode-textmate": "^4.2.2", "xterm": "3.15.0-beta71", "xterm-addon-search": "0.2.0-beta2", diff --git a/remote/web/package.json b/remote/web/package.json index 38f730e7da..c7a487b6c2 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -6,6 +6,7 @@ "vscode-textmate": "^4.1.1", "xterm": "3.15.0-beta67", "xterm-addon-search": "0.2.0-beta2", - "xterm-addon-web-links": "0.1.0-beta10" + "xterm-addon-web-links": "0.1.0-beta10", + "semver-umd": "^5.5.3" } } \ No newline at end of file diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 3f790e1f28..b624eb3729 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -19,6 +19,11 @@ oniguruma@^7.2.0: dependencies: nan "^2.14.0" +semver-umd@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" + integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== + vscode-textmate@^4.1.1: version "4.2.2" resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" diff --git a/remote/yarn.lock b/remote/yarn.lock index 7d522e2901..9aa7137893 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -876,16 +876,16 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +semver-umd@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" + integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== + semver@^5.3.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== -semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== - semver@^5.6.0: version "5.7.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" @@ -1123,10 +1123,10 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.3.1.tgz#51fb93debcd0c18a8b90dbc37f84f94333d0c486" - integrity sha512-4WLB/n4ZeWNi5AEzPTkfYrqbKtXlv0SlgmxbRVdulwZzGx/lfWeWPu9Shy32orM27IofQAQDuirbRBOYNJVzBA== +vscode-ripgrep@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.4.tgz#dae1c3eef350513299341cdf96e622c00b548eff" + integrity sha512-Bs8SvFAkR0QHf09J46VgNo19yRikOtj/f0zHzK3AM3ICjCGNN/BNoG9of6zGVHUTO+6Mk1RbKglyOHLKr8D1lg== vscode-textmate@^4.2.2: version "4.2.2" diff --git a/src/sql/platform/telemetry/test/common/telemetryUtilities.test.ts b/src/sql/platform/telemetry/test/common/telemetryUtilities.test.ts index bc3aca54ee..ff3645c5f2 100644 --- a/src/sql/platform/telemetry/test/common/telemetryUtilities.test.ts +++ b/src/sql/platform/telemetry/test/common/telemetryUtilities.test.ts @@ -8,7 +8,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import * as TypeMoq from 'typemoq'; import * as assert from 'assert'; import { NullLogService } from 'vs/platform/log/common/log'; -import { SimpleTelemetryService } from 'vs/workbench/browser/web.simpleservices'; +import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; suite('SQL Telemetry Utilities tests', () => { let telemetryService: TypeMoq.Mock; @@ -35,7 +35,7 @@ suite('SQL Telemetry Utilities tests', () => { }; setup(() => { - telemetryService = TypeMoq.Mock.ofType(SimpleTelemetryService, TypeMoq.MockBehavior.Strict); + telemetryService = TypeMoq.Mock.ofType(TelemetryService, TypeMoq.MockBehavior.Strict, Object.create(null)); telemetryService.setup(x => x.publicLog(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(x => Promise.resolve(none)); }); diff --git a/src/sql/workbench/electron-browser/modelComponents/webview.component.ts b/src/sql/workbench/electron-browser/modelComponents/webview.component.ts index 1a48ee2d9f..5b0520cd96 100644 --- a/src/sql/workbench/electron-browser/modelComponents/webview.component.ts +++ b/src/sql/workbench/electron-browser/modelComponents/webview.component.ts @@ -18,7 +18,7 @@ import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBa import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/workbench/browser/modelComponents/interfaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; import { WebviewContentOptions } from 'vs/workbench/contrib/webview/common/webview'; function reviveWebviewOptions(options: vscode.WebviewOptions): vscode.WebviewOptions { @@ -38,7 +38,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto']; - private _webview: WebviewElement; + private _webview: ElectronWebviewBasedWebview; private _renderedHtml: string; private _extensionLocationUri: URI; private _ready: Promise; @@ -65,7 +65,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen } private _createWebview(): void { - this._webview = this.instantiationService.createInstance(WebviewElement, + this._webview = this.instantiationService.createInstance(ElectronWebviewBasedWebview, { allowSvgs: true }, @@ -158,7 +158,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen this._ready.then(() => { super.setProperties(properties); if (this.options) { - this._webview.options = this.getExtendedOptions(); + this._webview.contentOptions = this.getExtendedOptions(); } if (this.html !== this._renderedHtml) { this.setHtml(); diff --git a/src/sql/workbench/parts/dashboard/electron-browser/contents/webviewContent.component.ts b/src/sql/workbench/parts/dashboard/electron-browser/contents/webviewContent.component.ts index c834397af6..59ff1ce55e 100644 --- a/src/sql/workbench/parts/dashboard/electron-browser/contents/webviewContent.component.ts +++ b/src/sql/workbench/parts/dashboard/electron-browser/contents/webviewContent.component.ts @@ -18,7 +18,7 @@ import { AngularDisposable } from 'sql/base/browser/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import * as azdata from 'azdata'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; @Component({ template: '', @@ -33,7 +33,7 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo public readonly onMessage: Event = this._onMessage.event; private _onMessageDisposable: IDisposable; - private _webview: WebviewElement; + private _webview: ElectronWebviewBasedWebview; private _html: string; constructor( @@ -100,7 +100,7 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo this._onMessageDisposable.dispose(); } - this._webview = this.instantiationService.createInstance(WebviewElement, + this._webview = this.instantiationService.createInstance(ElectronWebviewBasedWebview, {}, { allowScripts: true diff --git a/src/sql/workbench/parts/dashboard/electron-browser/widgets/webview/webviewWidget.component.ts b/src/sql/workbench/parts/dashboard/electron-browser/widgets/webview/webviewWidget.component.ts index 2a2bc3a999..86c0f6a878 100644 --- a/src/sql/workbench/parts/dashboard/electron-browser/widgets/webview/webviewWidget.component.ts +++ b/src/sql/workbench/parts/dashboard/electron-browser/widgets/webview/webviewWidget.component.ts @@ -16,7 +16,7 @@ import { IDashboardWebview, IDashboardViewService } from 'sql/platform/dashboard import * as azdata from 'azdata'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; interface IWebviewWidgetConfig { id: string; @@ -31,7 +31,7 @@ const selector = 'webview-widget'; export class WebviewWidget extends DashboardWidget implements IDashboardWidget, OnInit, IDashboardWebview { private _id: string; - private _webview: WebviewElement; + private _webview: ElectronWebviewBasedWebview; private _html: string; private _onMessage = new Emitter(); public readonly onMessage: Event = this._onMessage.event; @@ -99,7 +99,7 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget, this._onMessageDisposable.dispose(); } - this._webview = this.instantiationService.createInstance(WebviewElement, + this._webview = this.instantiationService.createInstance(ElectronWebviewBasedWebview, {}, { allowScripts: true, diff --git a/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts b/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts index 371558c659..f46a5c9399 100644 --- a/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts +++ b/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts @@ -5,17 +5,13 @@ import 'vs/css!./media/connectionViewletPanel'; import * as DOM from 'vs/base/browser/dom'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IExtensionTipsService, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { INotificationService } from 'vs/platform/notification/common/notification'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IAction } from 'vs/base/common/actions'; import { ServerTreeView } from 'sql/workbench/parts/objectExplorer/browser/serverTreeView'; import { @@ -23,12 +19,10 @@ import { AddServerAction, AddServerGroupAction } from 'sql/workbench/parts/objectExplorer/browser/connectionTreeAction'; import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService'; -import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; export class ConnectionViewletPanel extends ViewletPanel { private _root: HTMLElement; - private _toDisposeViewlet: IDisposable[] = []; private _serverTreeView: ServerTreeView; private _addServerAction: IAction; private _addServerGroupAction: IAction; @@ -36,17 +30,11 @@ export class ConnectionViewletPanel extends ViewletPanel { constructor( private options: IViewletViewOptions, - @INotificationService protected notificationService: INotificationService, @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, - @IInstantiationService protected instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService, - @IExtensionsWorkbenchService protected extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionTipsService protected tipsService: IExtensionTipsService, + @IInstantiationService private readonly instantiationService: IInstantiationService, @IConfigurationService configurationService: IConfigurationService, - @IWorkspaceContextService protected contextService: IWorkspaceContextService, - @IExtensionManagementServerService protected extensionManagementServerService: IExtensionManagementServerService, - @IObjectExplorerService private objectExplorerService: IObjectExplorerService + @IObjectExplorerService private readonly objectExplorerService: IObjectExplorerService ) { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService); this._addServerAction = this.instantiationService.createInstance(AddServerAction, diff --git a/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts b/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts index 0a8405f1d5..67ba75197d 100644 --- a/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts +++ b/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts @@ -16,7 +16,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { localize } from 'vs/nls'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import * as DOM from 'vs/base/browser/dom'; import { ILogService } from 'vs/platform/log/common/log'; @@ -27,7 +27,7 @@ export class WebViewDialog extends Modal { private _okButton: Button; private _okLabel: string; private _closeLabel: string; - private _webview: WebviewElement; + private _webview: ElectronWebviewBasedWebview; private _html: string; private _headerTitle: string; @@ -87,7 +87,7 @@ export class WebViewDialog extends Modal { protected renderBody(container: HTMLElement) { this._body = DOM.append(container, DOM.$('div.webview-dialog')); - this._webview = this._instantiationService.createInstance(WebviewElement, + this._webview = this._instantiationService.createInstance(ElectronWebviewBasedWebview, {}, { allowScripts: true diff --git a/src/typings/semver-umd.d.ts b/src/typings/semver-umd.d.ts new file mode 100644 index 0000000000..702dd75420 --- /dev/null +++ b/src/typings/semver-umd.d.ts @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'semver-umd' { + + export * from "semver"; + +} \ No newline at end of file diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 39e671c41c..1cb2676933 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -13,6 +13,7 @@ let _isWeb = false; let _locale: string | undefined = undefined; let _language: string = LANGUAGE_DEFAULT; let _translationsConfigFile: string | undefined = undefined; +let _userAgent: string | undefined = undefined; interface NLSConfig { locale: string; @@ -48,10 +49,10 @@ const isElectronRenderer = (typeof process !== 'undefined' && typeof process.ver // OS detection if (typeof navigator === 'object' && !isElectronRenderer) { - const userAgent = navigator.userAgent; - _isWindows = userAgent.indexOf('Windows') >= 0; - _isMacintosh = userAgent.indexOf('Macintosh') >= 0; - _isLinux = userAgent.indexOf('Linux') >= 0; + _userAgent = navigator.userAgent; + _isWindows = _userAgent.indexOf('Windows') >= 0; + _isMacintosh = _userAgent.indexOf('Macintosh') >= 0; + _isLinux = _userAgent.indexOf('Linux') >= 0; _isWeb = true; _locale = navigator.language; _language = _locale; @@ -108,6 +109,7 @@ export const isLinux = _isLinux; export const isNative = _isNative; export const isWeb = _isWeb; export const platform = _platform; +export const userAgent = _userAgent; export function isRootUser(): boolean { return _isNative && !_isWindows && (process.getuid() === 0); diff --git a/src/vs/base/node/cpuUsage.sh b/src/vs/base/node/cpuUsage.sh index 3d42b36dc2..8e07feffaf 100755 --- a/src/vs/base/node/cpuUsage.sh +++ b/src/vs/base/node/cpuUsage.sh @@ -30,7 +30,7 @@ for PID in "$@"; do fi PROCESS_BEFORE_TIMES[$ITER]=$PROCESS_TIME_BEFORE - ((ITER++)) + ((++ITER)) done # Wait for a second @@ -60,5 +60,5 @@ for PID in "$@"; do # Parent script reads from stdout, so echo result to be read echo $CPU_USAGE - ((ITER++)) + ((++ITER)) done diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 64b9617fe1..45d68976b9 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -23,7 +23,7 @@ export interface IChannel { } /** - * An `IServerChannel` is the couter part to `IChannel`, + * An `IServerChannel` is the counter part to `IChannel`, * on the server-side. You should implement this interface * if you'd like to handle remote promises or events. */ diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index 1e74244704..829ce5e4ae 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -10,7 +10,7 @@ + content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote:; media-src 'none'; child-src 'self' {{WEBVIEW_ENDPOINT}}; script-src 'self' https://az416426.vo.msecnd.net 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: https:; font-src 'self' blob: vscode-remote:;"> @@ -27,6 +27,9 @@ + + + diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js index a59f43e1e0..069fb4cff3 100644 --- a/src/vs/code/browser/workbench/workbench.js +++ b/src/vs/code/browser/workbench/workbench.js @@ -15,6 +15,7 @@ 'xterm': `${window.location.origin}/node_modules/xterm/lib/xterm.js`, 'xterm-addon-search': `${window.location.origin}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, 'xterm-addon-web-links': `${window.location.origin}/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, + 'semver-umd': `${window.location.origin}/node_modules/semver-umd/lib/semver-umd.js`, } }); diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 54ecf43cdf..7ce1609c4c 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -312,7 +312,7 @@ export class IssueReporter extends Disposable { const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)); const commonProperties = resolveCommonProperties(product.commit || 'Commit unknown', pkg.version, configuration.machineId, this.environmentService.installSourcePath); - const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; + const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; const telemetryService = instantiationService.createInstance(TelemetryService, config); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index db2559f4fa..50f6ee2ae7 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -13,7 +13,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; +import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; @@ -158,7 +158,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const config: ITelemetryServiceConfig = { appender: combinedAppender(appInsightsAppender, new LogAppender(logService)), commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, installSourcePath), - piiPaths: [appRoot, extensionsPath] + piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot] }; telemetryService = new TelemetryService(config, configurationService); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index f5a9de9d30..5628e42dc8 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -86,6 +86,7 @@ import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc' import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; export class CodeApplication extends Disposable { @@ -240,6 +241,7 @@ export class CodeApplication extends Disposable { context: OpenContext.DOCK /* can also be opening from finder while app is running */, cli: this.environmentService.args, urisToOpen: macOpenFileURIs, + gotoLineMode: false, preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */ }); @@ -279,12 +281,6 @@ export class CodeApplication extends Disposable { } }); - ipc.on('vscode:extensionHostDebug', (_: Event, windowId: number, broadcast: any) => { - if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:extensionHostDebug', broadcast, [windowId]); // Send to all windows (except sender window) - } - }); - ipc.on('vscode:toggleDevTools', (event: Event) => event.sender.toggleDevTools()); ipc.on('vscode:openDevTools', (event: Event) => event.sender.openDevTools()); @@ -484,7 +480,7 @@ export class CodeApplication extends Disposable { const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender'))); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)); const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath); - const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; + const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, trueMachineId }; services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); @@ -577,6 +573,9 @@ export class CodeApplication extends Disposable { electronIpcServer.registerChannel('loglevel', logLevelChannel); sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); + // ExtensionHost Debug broadcast service + electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); + // Signal phase: ready (services set) this.lifecycleService.phase = LifecycleMainPhase.Ready; @@ -597,8 +596,8 @@ export class CodeApplication extends Disposable { urlService.registerHandler({ async handleURL(uri: URI): Promise { if (windowsMainService.getWindowCount() === 0) { - const cli = { ...environmentService.args, goto: true }; - const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true }); + const cli = { ...environmentService.args }; + const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true, gotoLineMode: true }); await window.ready(); @@ -649,6 +648,7 @@ export class CodeApplication extends Disposable { urisToOpen: macOpenFiles.map(file => this.getURIToOpenFromPathSync(file)), noRecentEntry, waitMarkerFileURI, + gotoLineMode: false, initialStartup: true }); } @@ -661,6 +661,7 @@ export class CodeApplication extends Disposable { diffMode: args.diff, noRecentEntry, waitMarkerFileURI, + gotoLineMode: args.goto, initialStartup: true }); } diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 14ea0e476a..647ce03a82 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -334,7 +334,9 @@ class CodeMain { if (error.code === 'EACCES' || error.code === 'EPERM') { this.showStartupWarningDialog( localize('startupDataDirError', "Unable to write program user data."), - localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath) + environmentService.extensionsPath + ? localize('startupUserDataAndExtensionsDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath) + : localize('startupUserDataDirErrorDetail', "Please make sure the directory {0} is writeable.", environmentService.userDataPath) ); } } diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 5ba81dfeea..35f7fdc4ec 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -844,8 +844,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private doExtractPathsFromAPI(openConfig: IOpenConfiguration): IPathToOpen[] { const pathsToOpen: IPathToOpen[] = []; - const cli = openConfig.cli; - const parseOptions: IPathParseOptions = { gotoLineMode: cli && cli.goto }; + const parseOptions: IPathParseOptions = { gotoLineMode: openConfig.gotoLineMode }; for (const pathToOpen of openConfig.urisToOpen || []) { if (!pathToOpen) { continue; diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index b4374931e4..0ef2e21193 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import product from 'vs/platform/product/node/product'; import pkg from 'vs/platform/product/node/package'; import * as path from 'vs/base/common/path'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -102,7 +102,7 @@ export class Main { const ids: string[] = typeof arg === 'string' ? [arg] : arg; await this.locateExtension(ids); } else if (argv['telemetry']) { - console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath)); + console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath ? this.environmentService.extensionsPath : undefined)); } } @@ -293,7 +293,8 @@ export async function main(argv: ParsedArgs): Promise { process.once('exit', () => logService.dispose()); logService.info('main', argv); - await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath].map(p => mkdirp(p))); + await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath] + .map((path): undefined | Promise => path ? mkdirp(path) : undefined)); const configurationService = new ConfigurationService(environmentService.settingsResource); disposables.add(configurationService); @@ -339,7 +340,7 @@ export async function main(argv: ParsedArgs): Promise { const config: ITelemetryServiceConfig = { appender: combinedAppender(...appenders), commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), installSourcePath), - piiPaths: [appRoot, extensionsPath] + piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot] }; services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index bd498c008b..32766b14c2 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -451,6 +451,7 @@ export class Minimap extends ViewPart { private _options: MinimapOptions; private _lastRenderData: RenderData | null; + private _lastDecorations: ViewModelDecoration[] | undefined; private _renderDecorations: boolean = false; private _buffers: MinimapBuffers | null; @@ -675,6 +676,13 @@ export class Minimap extends ViewPart { return true; } + public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean { + this._context.model.invalidateMinimapColorCache(); + // Only bother calling render if decorations are currently shown + this._renderDecorations = !!this._lastDecorations; + return !!this._lastDecorations; + } + // --- end event handlers public prepareRender(ctx: RenderingContext): void { @@ -751,6 +759,8 @@ export class Minimap extends ViewPart { this.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration, layout, line, height, lineHeight, tabSize, characterWidth); } } + + this._lastDecorations = decorations; } } diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 5a8805bf3b..b55b3a6391 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -2703,6 +2703,10 @@ export class ModelDecorationMinimapOptions extends DecorationOptions { return this._resolvedColor; } + public invalidateCachedColor(): void { + this._resolvedColor = undefined; + } + private _resolveColor(color: string | ThemeColor, theme: ITheme): Color | undefined { if (typeof color === 'string') { return Color.fromHex(color); diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index a7b1cea0cb..52177b7fd8 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1285,7 +1285,7 @@ export interface CommentThread { commentThreadHandle: number; controllerHandle: number; extensionId?: string; - threadId: string | null; + threadId: string; resource: string | null; range: IRange; label: string; @@ -1333,8 +1333,7 @@ export enum CommentMode { * @internal */ export interface Comment { - readonly commentId: string; - readonly uniqueIdInThread?: number; + readonly uniqueIdInThread: number; readonly body: IMarkdownString; readonly userName: string; readonly userIconPath?: string; diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts index 9fe4195b39..ab355a699b 100644 --- a/src/vs/editor/common/view/editorColorRegistry.ts +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; -import { activeContrastBorder, editorBackground, editorForeground, registerColor, editorWarningForeground, editorInfoForeground, editorWarningBorder, editorInfoBorder } from 'vs/platform/theme/common/colorRegistry'; +import { activeContrastBorder, editorBackground, editorForeground, registerColor, editorWarningForeground, editorInfoForeground, editorWarningBorder, editorInfoBorder, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; /** @@ -31,7 +31,7 @@ export const editorRuler = registerColor('editorRuler.foreground', { dark: '#5A5 export const editorCodeLensForeground = registerColor('editorCodeLens.foreground', { dark: '#999999', light: '#999999', hc: '#999999' }, nls.localize('editorCodeLensForeground', 'Foreground color of editor code lenses')); export const editorBracketMatchBackground = registerColor('editorBracketMatch.background', { dark: '#0064001a', light: '#0064001a', hc: '#0064001a' }, nls.localize('editorBracketMatchBackground', 'Background color behind matching brackets')); -export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hc: '#fff' }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes')); +export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hc: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes')); export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hc: '#7f7f7f4d' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.')); diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 2435a223a7..3b15be4d78 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -141,6 +141,7 @@ export interface IViewModel { getLineLastNonWhitespaceColumn(lineNumber: number): number; getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations; invalidateOverviewRulerColorCache(): void; + invalidateMinimapColorCache(): void; getValueInRange(range: Range, eol: EndOfLinePreference): string; getModelLineMaxColumn(modelLineNumber: number): number; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 74ed9c3a84..47729c8921 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -11,7 +11,7 @@ import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions } from 'vs/editor/common/model'; -import { ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModel'; +import { ModelDecorationOverviewRulerOptions, ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; import { ColorId, LanguageId, TokenizationRegistry } from 'vs/editor/common/modes'; import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer'; @@ -565,6 +565,16 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } } + public invalidateMinimapColorCache(): void { + const decorations = this.model.getAllDecorations(); + for (const decoration of decorations) { + const opts = decoration.options.minimap; + if (opts) { + opts.invalidateCachedColor(); + } + } + } + public getValueInRange(range: Range, eol: EndOfLinePreference): string { const modelRange = this.coordinatesConverter.convertViewRangeToModelRange(range); return this.model.getValueInRange(modelRange, eol); diff --git a/src/vs/workbench/services/extensions/common/extensionHostDebug.ts b/src/vs/platform/debug/common/extensionHostDebug.ts similarity index 100% rename from src/vs/workbench/services/extensions/common/extensionHostDebug.ts rename to src/vs/platform/debug/common/extensionHostDebug.ts diff --git a/src/vs/platform/debug/common/extensionHostDebugIpc.ts b/src/vs/platform/debug/common/extensionHostDebugIpc.ts new file mode 100644 index 0000000000..c15072a9c3 --- /dev/null +++ b/src/vs/platform/debug/common/extensionHostDebugIpc.ts @@ -0,0 +1,99 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent, IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IRemoteConsoleLog } from 'vs/base/common/console'; + +export class ExtensionHostDebugBroadcastChannel implements IServerChannel { + + static readonly ChannelName = 'extensionhostdebugservice'; + + private _onCloseEmitter = new Emitter(); + private _onReloadEmitter = new Emitter(); + private _onTerminateEmitter = new Emitter(); + private _onLogToEmitter = new Emitter(); + private _onAttachEmitter = new Emitter(); + + call(ctx: TContext, command: string, arg?: any): Promise { + switch (command) { + case 'close': + return Promise.resolve(this._onCloseEmitter.fire({ sessionId: arg[0] })); + case 'reload': + return Promise.resolve(this._onReloadEmitter.fire({ sessionId: arg[0] })); + case 'terminate': + return Promise.resolve(this._onTerminateEmitter.fire({ sessionId: arg[0] })); + case 'log': + return Promise.resolve(this._onLogToEmitter.fire({ sessionId: arg[0], log: arg[1] })); + case 'attach': + return Promise.resolve(this._onAttachEmitter.fire({ sessionId: arg[0], port: arg[1], subId: arg[2] })); + } + throw new Error('Method not implemented.'); + } + + listen(ctx: TContext, event: string, arg?: any): Event { + switch (event) { + case 'close': + return this._onCloseEmitter.event; + case 'reload': + return this._onReloadEmitter.event; + case 'terminate': + return this._onTerminateEmitter.event; + case 'log': + return this._onLogToEmitter.event; + case 'attach': + return this._onAttachEmitter.event; + } + throw new Error('Method not implemented.'); + } +} + +export class ExtensionHostDebugChannelClient implements IExtensionHostDebugService { + + _serviceBrand: any; + + constructor(private channel: IChannel) { } + + reload(sessionId: string): void { + this.channel.call('reload', [sessionId]); + } + + get onReload(): Event { + return this.channel.listen('reload'); + } + + close(sessionId: string): void { + this.channel.call('close', [sessionId]); + } + + get onClose(): Event { + return this.channel.listen('close'); + } + + attachSession(sessionId: string, port: number, subId?: string): void { + this.channel.call('attach', [sessionId, port, subId]); + } + + get onAttachSession(): Event { + return this.channel.listen('attach'); + } + + logToSession(sessionId: string, log: IRemoteConsoleLog): void { + this.channel.call('log', [sessionId, log]); + } + + get onLogToSession(): Event { + return this.channel.listen('log'); + } + + terminateSession(sessionId: string, subId?: string): void { + this.channel.call('terminate', [sessionId, subId]); + } + + get onTerminateSession(): Event { + return this.channel.listen('terminate'); + } +} \ No newline at end of file diff --git a/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts index 7ce6ceeb4d..917d81b4c2 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts @@ -520,14 +520,17 @@ export class DiagnosticsService implements IDiagnosticsService { if (folderUri.scheme === 'file') { const folder = folderUri.fsPath; collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => { - /* __GDPR__ - "workspace.stats" : { - "fileTypes" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "configTypes" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "launchConfigs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('workspace.stats', { + type WorkspaceStatsClassification = { + fileTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + configTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + launchConfigs: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WorkspaceStatsEvent = { + fileTypes: WorkspaceStatItem[]; + configTypes: WorkspaceStatItem[]; + launchConfigs: WorkspaceStatItem[]; + }; + this.telemetryService.publicLog2('workspace.stats', { fileTypes: stats.fileTypes, configTypes: stats.configFiles, launchConfigs: stats.launchConfigFiles diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index c73ff3f2e1..ad118ecd0f 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -140,7 +140,7 @@ export interface IEnvironmentService { isExtensionDevelopment: boolean; disableExtensions: boolean | string[]; builtinExtensionsPath: string; - extensionsPath: string; + extensionsPath?: string; extensionDevelopmentLocationURI?: URI[]; extensionTestsLocationURI?: URI; @@ -178,4 +178,6 @@ export interface IEnvironmentService { webviewEndpoint?: string; readonly webviewResourceRoot: string; readonly webviewCspSource: string; + + readonly galleryMachineIdResource?: URI; } diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index d8e76f0691..d7e1af56b1 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -266,6 +266,9 @@ export class EnvironmentService implements IEnvironmentService { @memoize get nodeCachedDataDir(): string | undefined { return process.env['VSCODE_NODE_CACHED_DATA_DIR'] || undefined; } + @memoize + get galleryMachineIdResource(): URI { return resources.joinPath(URI.file(this.userDataPath), 'machineid'); } + get disableUpdates(): boolean { return !!this._args['disable-updates']; } get disableCrashReporter(): boolean { return !!this._args['disable-crash-reporter']; } diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 155cc56a2c..e48e1d8909 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -9,7 +9,7 @@ import { getGalleryExtensionId, getGalleryExtensionTelemetryData, adoptToGallery import { assign, getOrDefault } from 'vs/base/common/objects'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IPager } from 'vs/base/common/paging'; -import { IRequestService, IRequestOptions, IRequestContext, asJson, asText } from 'vs/platform/request/common/request'; +import { IRequestService, IRequestOptions, IRequestContext, asJson, asText, IHeaders } from 'vs/platform/request/common/request'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { generateUuid, isUUID } from 'vs/base/common/uuid'; @@ -467,13 +467,15 @@ export class ExtensionGalleryService implements IExtensionGalleryService { let text = options.text || ''; const pageSize = getOrDefault(options, o => o.pageSize, 50); - /* __GDPR__ - "galleryService:query" : { - "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "text": { "classification": "CustomerContent", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('galleryService:query', { type, text }); + type GalleryServiceQueryClassification = { + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + text: { classification: 'CustomerContent', purpose: 'FeatureInsight' }; + }; + type GalleryServiceQueryEvent = { + type: string; + text: string; + }; + this.telemetryService.publicLog2('galleryService:query', { type, text }); let query = new Query() .withFlags(Flags.IncludeLatestVersionOnly, Flags.IncludeAssetUri, Flags.IncludeStatistics, Flags.IncludeFiles, Flags.IncludeVersionProperties) @@ -943,29 +945,30 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService): Promise<{ [key: string]: string; }> { - const marketplaceMachineIdFile = joinPath(URI.file(environmentService.userDataPath), 'machineid'); - - let uuid: string | null = null; - - try { - const contents = await fileService.readFile(marketplaceMachineIdFile); - const value = contents.value.toString(); - uuid = isUUID(value) ? value : null; - } catch (e) { - uuid = null; - } - - if (!uuid) { - uuid = generateUuid(); - try { - await fileService.writeFile(marketplaceMachineIdFile, VSBuffer.fromString(uuid)); - } catch (error) { - //noop - } - } - return { + const headers: IHeaders = { 'X-Market-Client-Id': `VSCode ${version}`, - 'User-Agent': `VSCode ${version}`, - 'X-Market-User-Id': uuid + 'User-Agent': `VSCode ${version}` }; + let uuid: string | null = null; + if (environmentService.galleryMachineIdResource) { + try { + const contents = await fileService.readFile(environmentService.galleryMachineIdResource); + const value = contents.value.toString(); + uuid = isUUID(value) ? value : null; + } catch (e) { + uuid = null; + } + + if (!uuid) { + uuid = generateUuid(); + try { + await fileService.writeFile(environmentService.galleryMachineIdResource, VSBuffer.fromString(uuid)); + } catch (error) { + //noop + } + } + headers['X-Market-User-Id'] = uuid; + } + return headers; + } \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 4cc984c8bf..4fafc347a2 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -8,7 +8,6 @@ import { Event } from 'vs/base/common/event'; import { IPager } from 'vs/base/common/paging'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; -import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions'; @@ -210,110 +209,6 @@ export interface IExtensionManagementService { updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise; } -export const IExtensionManagementServerService = createDecorator('extensionManagementServerService'); - -export interface IExtensionManagementServer { - extensionManagementService: IExtensionManagementService; - authority: string; - label: string; -} - -export interface IExtensionManagementServerService { - _serviceBrand: any; - readonly localExtensionManagementServer: IExtensionManagementServer; - readonly remoteExtensionManagementServer: IExtensionManagementServer | null; - getExtensionManagementServer(location: URI): IExtensionManagementServer | null; -} - -export const enum EnablementState { - Disabled, - WorkspaceDisabled, - Enabled, - WorkspaceEnabled -} - -export const IExtensionEnablementService = createDecorator('extensionEnablementService'); - -export interface IExtensionEnablementService { - _serviceBrand: any; - - readonly allUserExtensionsDisabled: boolean; - - /** - * Event to listen on for extension enablement changes - */ - onEnablementChanged: Event; - - /** - * Returns the enablement state for the given extension - */ - getEnablementState(extension: IExtension): EnablementState; - - /** - * Returns `true` if the enablement can be changed. - */ - canChangeEnablement(extension: IExtension): boolean; - - /** - * Returns `true` if the given extension identifier is enabled. - */ - isEnabled(extension: IExtension): boolean; - - /** - * Enable or disable the given extension. - * if `workspace` is `true` then enablement is done for workspace, otherwise globally. - * - * Returns a promise that resolves to boolean value. - * if resolves to `true` then requires restart for the change to take effect. - * - * Throws error if enablement is requested for workspace and there is no workspace - */ - setEnablement(extensions: IExtension[], state: EnablementState): Promise; -} - -export interface IExtensionsConfigContent { - recommendations: string[]; - unwantedRecommendations: string[]; -} - -export type RecommendationChangeNotification = { - extensionId: string, - isRecommended: boolean -}; - -export type DynamicRecommendation = 'dynamic'; -export type ExecutableRecommendation = 'executable'; -export type CachedRecommendation = 'cached'; -export type ApplicationRecommendation = 'application'; -export type ExtensionRecommendationSource = IWorkspace | IWorkspaceFolder | URI | DynamicRecommendation | ExecutableRecommendation | CachedRecommendation | ApplicationRecommendation; - -export interface IExtensionRecommendation { - extensionId: string; - sources: ExtensionRecommendationSource[]; -} - -export const IExtensionTipsService = createDecorator('extensionTipsService'); - -export interface IExtensionTipsService { - _serviceBrand: any; - getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; }; - getFileBasedRecommendations(): IExtensionRecommendation[]; - getOtherRecommendations(): Promise; - getWorkspaceRecommendations(): Promise; - getKeymapRecommendations(): IExtensionRecommendation[]; - toggleIgnoredRecommendation(extensionId: string, shouldIgnore: boolean): void; - getAllIgnoredRecommendations(): { global: string[], workspace: string[] }; - onRecommendationChange: Event; -} - -export const enum ExtensionRecommendationReason { - Workspace, - File, - Executable, - DynamicWorkspace, - Experimental -} - export const ExtensionsLabel = localize('extensions', "Extensions"); export const ExtensionsChannelId = 'extensions'; export const PreferencesLabel = localize('preferences', "Preferences"); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts similarity index 100% rename from src/vs/platform/extensionManagement/node/extensionManagementIpc.ts rename to src/vs/platform/extensionManagement/common/extensionManagementIpc.ts diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index a1e910b603..e71e2ded79 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -26,7 +26,7 @@ import { localizeManifest } from '../common/extensionNls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Limiter, createCancelablePromise, CancelablePromise, Queue } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import { URI } from 'vs/base/common/uri'; import pkg from 'vs/platform/product/node/package'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; @@ -138,7 +138,7 @@ export class ExtensionManagementService extends Disposable implements IExtension ) { super(); this.systemExtensionsPath = environmentService.builtinExtensionsPath; - this.extensionsPath = environmentService.extensionsPath; + this.extensionsPath = environmentService.extensionsPath!; this.uninstalledPath = path.join(this.extensionsPath, '.obsolete'); this.uninstalledFileLimiter = new Queue(); this.manifestCache = this._register(new ExtensionsManifestCache(environmentService, this)); diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index 883e8a6dba..09ac10ac0d 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -228,7 +228,8 @@ export class LaunchService implements ILaunchService { diffMode: args.diff, addMode: args.add, noRecentEntry: !!args['skip-add-to-recently-opened'], - waitMarkerFileURI + waitMarkerFileURI, + gotoLineMode: args.goto }); } diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 3769106d68..31b14a816e 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -487,7 +487,8 @@ export class Menubar { context: OpenContext.MENU, cli: this.environmentService.args, urisToOpen: [uriToOpen], - forceNewWindow: openInNewWindow + forceNewWindow: openInNewWindow, + gotoLineMode: false }).length > 0; if (!success) { diff --git a/src/vs/platform/product/browser/productService.ts b/src/vs/platform/product/browser/productService.ts index eae55c7287..f1abde0c15 100644 --- a/src/vs/platform/product/browser/productService.ts +++ b/src/vs/platform/product/browser/productService.ts @@ -21,7 +21,7 @@ export class ProductService implements IProductService { get vscodeVersion(): string { return '1.35.0'; } // {{SQL CARBON EDIT}} add vscodeversion - get commit(): string | undefined { return undefined; } + get commit(): string | undefined { return this.productConfiguration ? this.productConfiguration.commit : undefined; } get nameLong(): string { return ''; } @@ -46,4 +46,6 @@ export class ProductService implements IProductService { get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return this.productConfiguration ? this.productConfiguration.extensionKeywords : undefined; } get extensionAllowedBadgeProviders(): readonly string[] | undefined { return this.productConfiguration ? this.productConfiguration.extensionAllowedBadgeProviders : undefined; } + + get aiConfig() { return this.productConfiguration ? this.productConfiguration.aiConfig : undefined; } } \ No newline at end of file diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 9422ae415c..a14c7675b7 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -38,6 +38,10 @@ export interface IProductService { readonly experimentsUrl?: string; readonly extensionKeywords?: { [extension: string]: readonly string[]; }; readonly extensionAllowedBadgeProviders?: readonly string[]; + + readonly aiConfig?: { + readonly asimovKey: string; + }; } export interface IProductConfiguration { diff --git a/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts b/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts new file mode 100644 index 0000000000..7c7ba03bd3 --- /dev/null +++ b/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; + +export const instanceStorageKey = 'telemetry.instanceId'; +export const currentSessionDateStorageKey = 'telemetry.currentSessionDate'; +export const firstSessionDateStorageKey = 'telemetry.firstSessionDate'; +export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; + +import * as Platform from 'vs/base/common/platform'; +import * as uuid from 'vs/base/common/uuid'; + +export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> { + const result: { [name: string]: string | undefined; } = Object.create(null); + const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!; + const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!; + const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!; + + // __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.firstSessionDate'] = firstSessionDate; + // __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.lastSessionDate'] = lastSessionDate || ''; + // __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.isNewSession'] = !lastSessionDate ? '1' : '0'; + // __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.instanceId'] = instanceId; + // __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority); + + // __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } + result['common.machineId'] = machineId; + // __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['sessionID'] = uuid.generateUuid() + Date.now(); + // __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + result['commitHash'] = commit; + // __GDPR__COMMON__ "version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['version'] = version; + // __GDPR__COMMON__ "common.platform" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.platform'] = Platform.PlatformToString(Platform.platform); + // __GDPR__COMMON__ "common.product" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + result['common.product'] = 'web'; + // __GDPR__COMMON__ "common.userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.userAgent'] = Platform.userAgent; + + // dynamic properties which value differs on each call + let seq = 0; + const startTime = Date.now(); + Object.defineProperties(result, { + // __GDPR__COMMON__ "timestamp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + 'timestamp': { + get: () => new Date(), + enumerable: true + }, + // __GDPR__COMMON__ "common.timesincesessionstart" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + 'common.timesincesessionstart': { + get: () => Date.now() - startTime, + enumerable: true + }, + // __GDPR__COMMON__ "common.sequence" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + 'common.sequence': { + get: () => seq++, + enumerable: true + } + }); + + return result; +} + +function cleanRemoteAuthority(remoteAuthority?: string): string { + if (!remoteAuthority) { + return 'none'; + } + + let ret = 'other'; + // Whitelisted remote authorities + ['ssh-remote', 'dev-container', 'wsl'].forEach((res: string) => { + if (remoteAuthority!.indexOf(`${res}+`) === 0) { + ret = res; + } + }); + + return ret; +} diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index e1fe787c45..04066a752b 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -9,6 +9,8 @@ import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/com import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { ILogService } from 'vs/platform/log/common/log'; import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; +import { safeStringify } from 'vs/base/common/objects'; +import { isObject } from 'vs/base/common/types'; export const NullTelemetryService = new class implements ITelemetryService { _serviceBrand: undefined; @@ -243,6 +245,77 @@ export function keybindingsTelemetry(telemetryService: ITelemetryService, keybin }); } + +export interface Properties { + [key: string]: string; +} + +export interface Measurements { + [key: string]: number; +} + +export function validateTelemetryData(data?: any): { properties: Properties, measurements: Measurements } { + + const properties: Properties = Object.create(null); + const measurements: Measurements = Object.create(null); + + const flat = Object.create(null); + flatten(data, flat); + + for (let prop in flat) { + // enforce property names less than 150 char, take the last 150 char + prop = prop.length > 150 ? prop.substr(prop.length - 149) : prop; + const value = flat[prop]; + + if (typeof value === 'number') { + measurements[prop] = value; + + } else if (typeof value === 'boolean') { + measurements[prop] = value ? 1 : 0; + + } else if (typeof value === 'string') { + //enforce property value to be less than 1024 char, take the first 1024 char + properties[prop] = value.substring(0, 1023); + + } else if (typeof value !== 'undefined' && value !== null) { + properties[prop] = value; + } + } + + return { + properties, + measurements + }; +} + +function flatten(obj: any, result: { [key: string]: any }, order: number = 0, prefix?: string): void { + if (!obj) { + return; + } + + for (let item of Object.getOwnPropertyNames(obj)) { + const value = obj[item]; + const index = prefix ? prefix + item : item; + + if (Array.isArray(value)) { + result[index] = safeStringify(value); + + } else if (value instanceof Date) { + // TODO unsure why this is here and not in _getData + result[index] = value.toISOString(); + + } else if (isObject(value)) { + if (order < 2) { + flatten(value, result, order + 1, index + '.'); + } else { + result[index] = safeStringify(value); + } + } else { + result[index] = value; + } + } +} + function flattenKeys(value: Object | undefined): string[] { if (!value) { return []; diff --git a/src/vs/platform/telemetry/node/appInsightsAppender.ts b/src/vs/platform/telemetry/node/appInsightsAppender.ts index 17e606b89c..a3a3bd7003 100644 --- a/src/vs/platform/telemetry/node/appInsightsAppender.ts +++ b/src/vs/platform/telemetry/node/appInsightsAppender.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as appInsights from 'applicationinsights'; -import { isObject } from 'vs/base/common/types'; -import { safeStringify, mixin } from 'vs/base/common/objects'; -import { ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils'; +import { mixin } from 'vs/base/common/objects'; +import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; import { ILogService } from 'vs/platform/log/common/log'; function getClient(aiKey: string): appInsights.TelemetryClient { @@ -35,13 +34,6 @@ function getClient(aiKey: string): appInsights.TelemetryClient { return client; } -interface Properties { - [key: string]: string; -} - -interface Measurements { - [key: string]: number; -} export class AppInsightsAppender implements ITelemetryAppender { @@ -64,74 +56,12 @@ export class AppInsightsAppender implements ITelemetryAppender { } } - private static _getData(data?: any): { properties: Properties, measurements: Measurements } { - - const properties: Properties = Object.create(null); - const measurements: Measurements = Object.create(null); - - const flat = Object.create(null); - AppInsightsAppender._flaten(data, flat); - - for (let prop in flat) { - // enforce property names less than 150 char, take the last 150 char - prop = prop.length > 150 ? prop.substr(prop.length - 149) : prop; - const value = flat[prop]; - - if (typeof value === 'number') { - measurements[prop] = value; - - } else if (typeof value === 'boolean') { - measurements[prop] = value ? 1 : 0; - - } else if (typeof value === 'string') { - //enforce property value to be less than 1024 char, take the first 1024 char - properties[prop] = value.substring(0, 1023); - - } else if (typeof value !== 'undefined' && value !== null) { - properties[prop] = value; - } - } - - return { - properties, - measurements - }; - } - - private static _flaten(obj: any, result: { [key: string]: any }, order: number = 0, prefix?: string): void { - if (!obj) { - return; - } - - for (let item of Object.getOwnPropertyNames(obj)) { - const value = obj[item]; - const index = prefix ? prefix + item : item; - - if (Array.isArray(value)) { - result[index] = safeStringify(value); - - } else if (value instanceof Date) { - // TODO unsure why this is here and not in _getData - result[index] = value.toISOString(); - - } else if (isObject(value)) { - if (order < 2) { - AppInsightsAppender._flaten(value, result, order + 1, index + '.'); - } else { - result[index] = safeStringify(value); - } - } else { - result[index] = value; - } - } - } - log(eventName: string, data?: any): void { if (!this._aiClient) { return; } data = mixin(data, this._defaultData); - data = AppInsightsAppender._getData(data); + data = validateTelemetryData(data); if (this._logService) { this._logService.trace(`telemetry/${eventName}`, data); diff --git a/src/vs/platform/telemetry/node/telemetry.ts b/src/vs/platform/telemetry/node/telemetry.ts index df0ecb92ed..c50f80f1c6 100644 --- a/src/vs/platform/telemetry/node/telemetry.ts +++ b/src/vs/platform/telemetry/node/telemetry.ts @@ -8,34 +8,36 @@ import { readdirSync } from 'vs/base/node/pfs'; import { statSync, readFileSync } from 'fs'; import { join } from 'vs/base/common/path'; -export function buildTelemetryMessage(appRoot: string, extensionsPath: string): string { - // Gets all the directories inside the extension directory - const dirs = readdirSync(extensionsPath).filter(files => { - // This handles case where broken symbolic links can cause statSync to throw and error - try { - return statSync(join(extensionsPath, files)).isDirectory(); - } catch { - return false; - } - }); - const telemetryJsonFolders: string[] = []; - dirs.forEach((dir) => { - const files = readdirSync(join(extensionsPath, dir)).filter(file => file === 'telemetry.json'); - // We know it contains a telemetry.json file so we add it to the list of folders which have one - if (files.length === 1) { - telemetryJsonFolders.push(dir); - } - }); +export function buildTelemetryMessage(appRoot: string, extensionsPath?: string): string { const mergedTelemetry = Object.create(null); // Simple function to merge the telemetry into one json object const mergeTelemetry = (contents: string, dirName: string) => { const telemetryData = JSON.parse(contents); mergedTelemetry[dirName] = telemetryData; }; - telemetryJsonFolders.forEach((folder) => { - const contents = readFileSync(join(extensionsPath, folder, 'telemetry.json')).toString(); - mergeTelemetry(contents, folder); - }); + if (extensionsPath) { + // Gets all the directories inside the extension directory + const dirs = readdirSync(extensionsPath).filter(files => { + // This handles case where broken symbolic links can cause statSync to throw and error + try { + return statSync(join(extensionsPath, files)).isDirectory(); + } catch { + return false; + } + }); + const telemetryJsonFolders: string[] = []; + dirs.forEach((dir) => { + const files = readdirSync(join(extensionsPath, dir)).filter(file => file === 'telemetry.json'); + // We know it contains a telemetry.json file so we add it to the list of folders which have one + if (files.length === 1) { + telemetryJsonFolders.push(dir); + } + }); + telemetryJsonFolders.forEach((folder) => { + const contents = readFileSync(join(extensionsPath, folder, 'telemetry.json')).toString(); + mergeTelemetry(contents, folder); + }); + } let contents = readFileSync(join(appRoot, 'telemetry-core.json')).toString(); mergeTelemetry(contents, 'vscode-core'); contents = readFileSync(join(appRoot, 'telemetry-extensions.json')).toString(); diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index ce9aa60cca..5dec8a1d57 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -273,8 +273,8 @@ export const editorErrorBorder = registerColor('editorError.border', { dark: nul export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#CCA700', light: '#E9A700', hc: null }, nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.')); export const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hc: Color.fromHex('#FFCC00').transparent(0.8) }, nls.localize('warningBorder', 'Border color of warning boxes in the editor.')); -export const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#008000', light: '#008000', hc: null }, nls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.')); -export const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hc: Color.fromHex('#71B771').transparent(0.8) }, nls.localize('infoBorder', 'Border color of info boxes in the editor.')); +export const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#75BEFF', light: '#75BEFF', hc: null }, nls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.')); +export const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hc: Color.fromHex('#75BEFF').transparent(0.8) }, nls.localize('infoBorder', 'Border color of info boxes in the editor.')); export const editorHintForeground = registerColor('editorHint.foreground', { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hc: null }, nls.localize('editorHint.foreground', 'Foreground color of hint squigglies in the editor.')); export const editorHintBorder = registerColor('editorHint.border', { dark: null, light: null, hc: Color.fromHex('#eeeeee').transparent(0.8) }, nls.localize('hintBorder', 'Border color of hint boxes in the editor.')); diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index d0785357c4..6d95d15318 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -18,6 +18,10 @@ export function createUpdateURL(platform: string, quality: string): string { return `${product.updateUrl}/api/update/${platform}/${quality}/${product.commit}`; } +export type UpdateNotAvailableClassification = { + explicit: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; +}; + export abstract class AbstractUpdateService implements IUpdateService { _serviceBrand: any; diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index 1341e007f1..aae7fed84c 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -13,7 +13,7 @@ import { State, IUpdate, StateType, UpdateType } from 'vs/platform/update/common import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; -import { AbstractUpdateService, createUpdateURL } from 'vs/platform/update/electron-main/abstractUpdateService'; +import { AbstractUpdateService, createUpdateURL, UpdateNotAvailableClassification } from 'vs/platform/update/electron-main/abstractUpdateService'; import { IRequestService } from 'vs/platform/request/common/request'; export class DarwinUpdateService extends AbstractUpdateService { @@ -81,12 +81,10 @@ export class DarwinUpdateService extends AbstractUpdateService { return; } - /* __GDPR__ - "update:downloaded" : { - "version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('update:downloaded', { version: update.version }); + type UpdateDownloadedClassification = { + version: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ version: String }, UpdateDownloadedClassification>('update:downloaded', { version: update.version }); this.setState(State.Ready(update)); } @@ -95,13 +93,7 @@ export class DarwinUpdateService extends AbstractUpdateService { if (this.state.type !== StateType.CheckingForUpdates) { return; } - - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!this.state.context }); + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!this.state.context }); this.setState(State.Idle(UpdateType.Archive)); } diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 6219940219..8efcbd3efb 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -10,7 +10,7 @@ import { State, IUpdate, AvailableForDownload, UpdateType } from 'vs/platform/up import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; -import { createUpdateURL, AbstractUpdateService } from 'vs/platform/update/electron-main/abstractUpdateService'; +import { createUpdateURL, AbstractUpdateService, UpdateNotAvailableClassification } from 'vs/platform/update/electron-main/abstractUpdateService'; import { IRequestService, asJson } from 'vs/platform/request/common/request'; import { shell } from 'electron'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -40,17 +40,11 @@ export class LinuxUpdateService extends AbstractUpdateService { } this.setState(State.CheckingForUpdates(context)); - this.requestService.request({ url: this.url }, CancellationToken.None) .then(asJson) .then(update => { if (!update || !update.url || !update.version || !update.productVersion) { - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!context }); + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); this.setState(State.Idle(UpdateType.Archive)); } else { @@ -59,14 +53,7 @@ export class LinuxUpdateService extends AbstractUpdateService { }) .then(undefined, err => { this.logService.error(err); - - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!context }); - + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); // only show message when explicitly checking for updates const message: string | undefined = !!context ? (err.message || err) : undefined; this.setState(State.Idle(UpdateType.Archive, message)); diff --git a/src/vs/platform/update/electron-main/updateService.snap.ts b/src/vs/platform/update/electron-main/updateService.snap.ts index b3cb7a8103..6a0c359a09 100644 --- a/src/vs/platform/update/electron-main/updateService.snap.ts +++ b/src/vs/platform/update/electron-main/updateService.snap.ts @@ -13,6 +13,7 @@ import * as path from 'vs/base/common/path'; import { realpath, watch } from 'fs'; import { spawn } from 'child_process'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { UpdateNotAvailableClassification } from 'vs/platform/update/electron-main/abstractUpdateService'; abstract class AbstractUpdateService2 implements IUpdateService { @@ -159,29 +160,17 @@ export class SnapUpdateService extends AbstractUpdateService2 { protected doCheckForUpdates(context: any): void { this.setState(State.CheckingForUpdates(context)); - this.isUpdateAvailable().then(result => { if (result) { this.setState(State.Ready({ version: 'something', productVersion: 'something' })); } else { - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!context }); + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); this.setState(State.Idle(UpdateType.Snap)); } }, err => { this.logService.error(err); - - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!context }); + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); this.setState(State.Idle(UpdateType.Snap, err.message || err)); }); } diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 351f0a0bbb..98d37398a6 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -14,7 +14,7 @@ import { State, IUpdate, StateType, AvailableForDownload, UpdateType } from 'vs/ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; -import { createUpdateURL, AbstractUpdateService } from 'vs/platform/update/electron-main/abstractUpdateService'; +import { createUpdateURL, AbstractUpdateService, UpdateNotAvailableClassification } from 'vs/platform/update/electron-main/abstractUpdateService'; import { IRequestService, asJson } from 'vs/platform/request/common/request'; import { checksum } from 'vs/base/node/crypto'; import { tmpdir } from 'os'; @@ -169,12 +169,7 @@ export class Win32UpdateService extends AbstractUpdateService { }) .then(undefined, err => { this.logService.error(err); - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!context }); + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); // only show message when explicitly checking for updates const message: string | undefined = !!context ? (err.message || err) : undefined; diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index c59eba5e0d..4593820f27 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -183,6 +183,7 @@ export interface IOpenSettings { forceReuseWindow?: boolean; diffMode?: boolean; addMode?: boolean; + gotoLineMode?: boolean; noRecentEntry?: boolean; waitMarkerFileURI?: URI; args?: ParsedArgs; diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 88b695be11..9aa3d63faa 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -132,6 +132,7 @@ export interface IOpenConfiguration { readonly forceEmpty?: boolean; readonly diffMode?: boolean; addMode?: boolean; + readonly gotoLineMode?: boolean; readonly initialStartup?: boolean; readonly noRecentEntry?: boolean; } diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 1cbef2b87c..c79d9340e0 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -295,6 +295,7 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH forceReuseWindow: options.forceReuseWindow, diffMode: options.diffMode, addMode: options.addMode, + gotoLineMode: options.gotoLineMode, noRecentEntry: options.noRecentEntry, waitMarkerFileURI: options.waitMarkerFileURI }); @@ -461,10 +462,10 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH } private openFileForURI(uri: IURIToOpen): void { - const cli = assign(Object.create(null), this.environmentService.args, { goto: true }); + const cli = assign(Object.create(null), this.environmentService.args); const urisToOpen = [uri]; - this.windowsMainService.open({ context: OpenContext.API, cli, urisToOpen }); + this.windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true }); } async resolveProxy(windowId: number, url: string): Promise { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index f215f12af0..4f66d1891a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -713,54 +713,6 @@ declare module 'vscode' { //#endregion - /** - * Comment Reactions - * Stay in proposed. - */ - interface CommentReaction { - readonly hasReacted?: boolean; - } - - /** - * Stay in proposed - */ - export interface CommentReactionProvider { - availableReactions: CommentReaction[]; - toggleReaction?(document: TextDocument, comment: Comment, reaction: CommentReaction): Promise; - } - - - export interface CommentController { - /** - * Optional reaction provider - * Stay in proposed. - */ - reactionProvider?: CommentReactionProvider; - } - - - /** - * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. - */ - export interface Comment { - /** - * The id of the comment - */ - commentId: string; - } - - /** - * A comment controller is able to provide [comments](#CommentThread) support to the editor and - * provide users various ways to interact with comments. - */ - export interface CommentController { - /** - * Optional reaction provider - */ - reactionProvider?: CommentReactionProvider; - } - - //#endregion //#region Terminal diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index 44994f2b86..f426840991 100644 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts @@ -8,7 +8,7 @@ import * as modes from 'vs/editor/common/modes'; import { MainContext, MainThreadEditorInsetsShape, IExtHostContext, ExtHostEditorInsetsShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from '../common/extHostCustomers'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview'; +import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/common/webview'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -33,7 +33,7 @@ class EditorWebviewZone implements IViewZone { readonly editor: IActiveCodeEditor, readonly line: number, readonly height: number, - readonly webview: Webview, + readonly webview: WebviewElement, ) { this.domNode = document.createElement('div'); this.domNode.style.zIndex = '10'; // without this, the webview is not interactive @@ -124,12 +124,11 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { $setHtml(handle: number, value: string): void { const inset = this.getInset(handle); inset.webview.html = value; - } $setOptions(handle: number, options: modes.IWebviewOptions): void { const inset = this.getInset(handle); - inset.webview.options = options; + inset.webview.contentOptions = options; } async $postMessage(handle: number, value: any): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 298ccc99f1..e9412e3105 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -308,10 +308,6 @@ export class MainThreadCommentController { return commentingRanges || []; } - getReactionGroup(): modes.CommentReaction[] | undefined { - return this._features.reactionGroup; - } - async toggleReaction(uri: URI, thread: modes.CommentThread, comment: modes.Comment, reaction: modes.CommentReaction, token: CancellationToken): Promise { return this._proxy.$toggleReaction(this._handle, thread.commentThreadHandle, uri, comment, reaction); } diff --git a/src/vs/workbench/api/browser/mainThreadConsole.ts b/src/vs/workbench/api/browser/mainThreadConsole.ts index 5e6e86b3b6..13a159bcbb 100644 --- a/src/vs/workbench/api/browser/mainThreadConsole.ts +++ b/src/vs/workbench/api/browser/mainThreadConsole.ts @@ -9,7 +9,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console'; import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; @extHostNamedCustomer(MainContext.MainThreadConsole) export class MainThreadConsole implements MainThreadConsoleShape { diff --git a/src/vs/workbench/api/browser/mainThreadExtensionService.ts b/src/vs/workbench/api/browser/mainThreadExtensionService.ts index fece587efc..8355249a29 100644 --- a/src/vs/workbench/api/browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/browser/mainThreadExtensionService.ts @@ -12,11 +12,12 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio import { INotificationService } from 'vs/platform/notification/common/notification'; import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions'; +import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; @extHostNamedCustomer(MainContext.MainThreadExtensionService) export class MainThreadExtensionService implements MainThreadExtensionServiceShape { @@ -25,18 +26,21 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha private readonly _notificationService: INotificationService; private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService; private readonly _windowService: IWindowService; + private readonly _extensionEnablementService: IExtensionEnablementService; constructor( extHostContext: IExtHostContext, @IExtensionService extensionService: IExtensionService, @INotificationService notificationService: INotificationService, @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, - @IWindowService windowService: IWindowService + @IWindowService windowService: IWindowService, + @IExtensionEnablementService extensionEnablementService: IExtensionEnablementService ) { this._extensionService = extensionService; this._notificationService = notificationService; this._extensionsWorkbenchService = extensionsWorkbenchService; this._windowService = windowService; + this._extensionEnablementService = extensionEnablementService; } public dispose(): void { @@ -74,30 +78,31 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha const local = await this._extensionsWorkbenchService.queryLocal(); const installedDependency = local.filter(i => areSameExtensions(i.identifier, { id: missingDependency }))[0]; if (installedDependency) { - await this._handleMissingInstalledDependency(extension, installedDependency); + await this._handleMissingInstalledDependency(extension, installedDependency.local!); } else { await this._handleMissingNotInstalledDependency(extension, missingDependency); } } } - private async _handleMissingInstalledDependency(extension: IExtensionDescription, missingInstalledDependency: IExtension): Promise { + private async _handleMissingInstalledDependency(extension: IExtensionDescription, missingInstalledDependency: ILocalExtension): Promise { const extName = extension.displayName || extension.name; - if (missingInstalledDependency.enablementState === EnablementState.Enabled || missingInstalledDependency.enablementState === EnablementState.WorkspaceEnabled) { + if (this._extensionEnablementService.isEnabled(missingInstalledDependency)) { this._notificationService.notify({ severity: Severity.Error, - message: localize('reload window', "Cannot activate the '{0}' extension because it depends on the '{1}' extension, which is not loaded. Would you like to reload the window to load the extension?", extName, missingInstalledDependency.displayName), + message: localize('reload window', "Cannot activate the '{0}' extension because it depends on the '{1}' extension, which is not loaded. Would you like to reload the window to load the extension?", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), actions: { primary: [new Action('reload', localize('reload', "Reload Window"), '', true, () => this._windowService.reloadWindow())] } }); } else { + const enablementState = this._extensionEnablementService.getEnablementState(missingInstalledDependency); this._notificationService.notify({ severity: Severity.Error, - message: localize('disabledDep', "Cannot activate the '{0}' extension because it depends on the '{1}' extension, which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.displayName), + message: localize('disabledDep', "Cannot activate the '{0}' extension because it depends on the '{1}' extension, which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), actions: { primary: [new Action('enable', localize('enable dep', "Enable and Reload"), '', true, - () => this._extensionsWorkbenchService.setEnablement([missingInstalledDependency], missingInstalledDependency.enablementState === EnablementState.Disabled ? EnablementState.Enabled : EnablementState.WorkspaceEnabled) + () => this._extensionEnablementService.setEnablement([missingInstalledDependency], enablementState === EnablementState.DisabledGlobally ? EnablementState.EnabledGlobally : EnablementState.EnabledWorkspace) .then(() => this._windowService.reloadWindow(), e => this._notificationService.error(e)))] } }); diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index 5578d77528..7778a92da9 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -14,7 +14,6 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/common/extHost.protocol'; import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; -import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -22,8 +21,9 @@ import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/commo import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { extHostNamedCustomer } from '../common/extHostCustomers'; import { IProductService } from 'vs/platform/product/common/product'; +import { startsWith } from 'vs/base/common/strings'; -interface MainThreadWebviewState { +interface OldMainThreadWebviewState { readonly viewType: string; state: any; } @@ -43,7 +43,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews private readonly _proxy: ExtHostWebviewsShape; - private readonly _webviews = new Map>(); + private readonly _webviews = new Map(); private readonly _revivers = new Map(); private _activeWebview: WebviewPanelHandle | undefined = undefined; @@ -67,8 +67,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews // This reviver's only job is to activate webview extensions // This should trigger the real reviver to be registered from the extension host side. this._register(_webviewEditorService.registerReviver({ - canRevive: (webview: WebviewEditorInput) => { - const viewType = webview.state && webview.state.viewType; + canRevive: (webview: WebviewEditorInput) => { + if (!webview.webview.state) { + return false; + } + + const viewType = this.fromInternalWebviewViewType(webview.viewType); if (typeof viewType === 'string') { extensionService.activateByEvent(`onWebviewPanel:${viewType}`); } @@ -96,11 +100,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews const webview = this._webviewEditorService.createWebview(handle, this.getInternalWebviewViewType(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), { location: URI.revive(extensionLocation), id: extensionId - }, this.createWebviewEventDelegate(handle)) as WebviewEditorInput; - webview.state = { - viewType: viewType, - state: undefined - }; + }); + this.hookupWebviewEventDelegate(handle, webview); this._webviews.set(handle, webview); @@ -129,12 +130,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews public $setHtml(handle: WebviewPanelHandle, value: string): void { const webview = this.getWebview(handle); - webview.html = value; + webview.webview.html = value; } public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void { const webview = this.getWebview(handle); - webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */)); + webview.webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */); } public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void { @@ -151,22 +152,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews public async $postMessage(handle: WebviewPanelHandle, message: any): Promise { const webview = this.getWebview(handle); - const editors = this._editorService.visibleControls - .filter(e => e instanceof WebviewEditor) - .map(e => e as WebviewEditor) - .filter(e => e.input!.matches(webview)); - - if (editors.length > 0) { - editors[0].sendMessage(message); - return true; - } - - if (webview.webview) { - webview.webview.sendMessage(message); - return true; - } - - return false; + webview.webview.sendMessage(message); + return true; } public $registerSerializer(viewType: string): void { @@ -175,28 +162,42 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } this._revivers.set(viewType, this._webviewEditorService.registerReviver({ - canRevive: (webview) => { - return webview.state && webview.state.viewType === viewType; + canRevive: (webviewEditorInput) => { + return !!webviewEditorInput.webview.state && webviewEditorInput.viewType === this.getInternalWebviewViewType(viewType); }, - reviveWebview: async (webview): Promise => { - const viewType = webview.state.viewType; - const handle = 'revival-' + MainThreadWebviews.revivalPool++; - this._webviews.set(handle, webview); - webview._events = this.createWebviewEventDelegate(handle); + reviveWebview: async (webviewEditorInput): Promise => { + const viewType = this.fromInternalWebviewViewType(webviewEditorInput.viewType); + if (!viewType) { + webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewEditorInput.viewType); + return; + } + + const handle = `revival-${MainThreadWebviews.revivalPool++}`; + this._webviews.set(handle, webviewEditorInput); + this.hookupWebviewEventDelegate(handle, webviewEditorInput); let state = undefined; - if (webview.state.state) { + if (webviewEditorInput.webview.state) { try { - state = JSON.parse(webview.state.state); + // Check for old-style webview state first which stored state inside another state object + // TODO: remove this after 1.37 ships. + if ( + typeof (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState).viewType === 'string' && + 'state' in (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState) + ) { + state = JSON.parse((webviewEditorInput.webview.state as any).state); + } else { + state = JSON.parse(webviewEditorInput.webview.state); + } } catch { // noop } } try { - await this._proxy.$deserializeWebviewPanel(handle, viewType, webview.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webview.group || 0), webview.options); + await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewEditorInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewEditorInput.group || 0), webviewEditorInput.webview.options); } catch (error) { onUnexpectedError(error); - webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); + webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); } } })); @@ -216,23 +217,28 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews return `mainThreadWebview-${viewType}`; } - private createWebviewEventDelegate(handle: WebviewPanelHandle) { - return { - onDidClickLink: (uri: URI) => this.onDidClickLink(handle, uri), - onMessage: (message: any) => this._proxy.$onMessage(handle, message), - onDispose: () => { - this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => { - this._webviews.delete(handle); - }); - }, - onDidUpdateWebviewState: (newState: any) => { - const webview = this.tryGetWebview(handle); - if (!webview || webview.isDisposed()) { - return; - } - (webview as WebviewEditorInput).state.state = newState; + private fromInternalWebviewViewType(viewType: string): string | undefined { + if (!startsWith(viewType, 'mainThreadWebview-')) { + return undefined; + } + return viewType.replace(/^mainThreadWebview-/, ''); + } + + private hookupWebviewEventDelegate(handle: WebviewPanelHandle, input: WebviewEditorInput) { + input.webview.onDidClickLink((uri: URI) => this.onDidClickLink(handle, uri)); + input.webview.onMessage((message: any) => this._proxy.$onMessage(handle, message)); + input.onDispose(() => { + this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => { + this._webviews.delete(handle); + }); + }); + input.webview.onDidUpdateState((newState: any) => { + const webview = this.tryGetWebview(handle); + if (!webview || webview.isDisposed()) { + return; } - }; + webview.webview.state = newState; + }); } private onActiveEditorChanged() { @@ -319,7 +325,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews if (this._productService.urlProtocol === link.scheme) { return true; } - return !!webview.options.enableCommandUris && link.scheme === 'command'; + return !!webview.webview.contentOptions.enableCommandUris && link.scheme === 'command'; } private getWebview(handle: WebviewPanelHandle): WebviewEditorInput { @@ -347,13 +353,15 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } } -function reviveWebviewOptions(options: WebviewInputOptions): WebviewInputOptions { +function reviveWebviewOptions(options: modes.IWebviewOptions): WebviewInputOptions { return { ...options, + allowScripts: options.enableScripts, localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined, }; } + function reviveWebviewIcon( value: { light: UriComponents, dark: UriComponents } | undefined ): { light: URI, dark: URI } | undefined { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index e28f95595c..4762748dc4 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1287,7 +1287,6 @@ export interface ExtHostCommentsShape { $updateCommentThreadTemplate(commentControllerHandle: number, threadHandle: number, range: IRange): Promise; $deleteCommentThread(commentControllerHandle: number, commentThreadHandle: number): void; $provideCommentingRanges(commentControllerHandle: number, uriComponents: UriComponents, token: CancellationToken): Promise; - $provideReactionGroup(commentControllerHandle: number): Promise; $toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise; } diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index 3827d36ee7..b6e6539604 100644 --- a/src/vs/workbench/api/common/extHostComments.ts +++ b/src/vs/workbench/api/common/extHostComments.ts @@ -187,47 +187,28 @@ export class ExtHostComments implements ExtHostCommentsShape, IDisposable { }).then(ranges => ranges ? ranges.map(x => extHostTypeConverter.Range.from(x)) : undefined); } - $provideReactionGroup(commentControllerHandle: number): Promise { - const commentController = this._commentControllers.get(commentControllerHandle); - - if (!commentController || !commentController.reactionProvider) { - return Promise.resolve(undefined); - } - - return asPromise(() => { - return commentController!.reactionProvider!.availableReactions; - }).then(reactions => reactions.map(reaction => convertToReaction(commentController.reactionProvider, reaction))); - } - $toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise { - const document = this._documents.getDocument(URI.revive(uri)); const commentController = this._commentControllers.get(commentControllerHandle); - if (!commentController || !((commentController.reactionProvider && commentController.reactionProvider.toggleReaction) || commentController.reactionHandler)) { + if (!commentController || !commentController.reactionHandler) { return Promise.resolve(undefined); } return asPromise(() => { const commentThread = commentController.getCommentThread(threadHandle); if (commentThread) { - const vscodeComment = commentThread.getComment(comment.commentId); + const vscodeComment = commentThread.getCommentByUniqueId(comment.uniqueIdInThread); if (commentController !== undefined && vscodeComment) { if (commentController.reactionHandler) { return commentController.reactionHandler(vscodeComment, convertFromReaction(reaction)); } - - if (commentController.reactionProvider && commentController.reactionProvider.toggleReaction) { - return commentController.reactionProvider.toggleReaction(document, vscodeComment, convertFromReaction(reaction)); - } } - } return Promise.resolve(undefined); }); } - dispose() { } @@ -391,16 +372,6 @@ export class ExtHostCommentThread implements vscode.CommentThread { ); } - getComment(commentId: string): vscode.Comment | undefined { - const comments = this._comments.filter(comment => comment.commentId === commentId); - - if (comments && comments.length) { - return comments[0]; - } - - return undefined; - } - getCommentByUniqueId(uniqueId: number): vscode.Comment | undefined { for (let key of this._commentsMap) { let comment = key[0]; @@ -442,19 +413,6 @@ class ExtHostCommentController implements vscode.CommentController { private _threads: Map = new Map(); commentingRangeProvider?: vscode.CommentingRangeProvider; - private _commentReactionProvider?: vscode.CommentReactionProvider; - - get reactionProvider(): vscode.CommentReactionProvider | undefined { - return this._commentReactionProvider; - } - - set reactionProvider(provider: vscode.CommentReactionProvider | undefined) { - this._commentReactionProvider = provider; - if (provider) { - this._proxy.$updateCommentControllerFeatures(this.handle, { reactionGroup: provider.availableReactions.map(reaction => convertToReaction(provider, reaction)) }); - } - } - private _reactionHandler?: ReactionHandler; get reactionHandler(): ReactionHandler | undefined { @@ -537,7 +495,6 @@ function convertToModeComment(thread: ExtHostCommentThread, commentController: E const iconPath = vscodeComment.author && vscodeComment.author.iconPath ? vscodeComment.author.iconPath.toString() : undefined; return { - commentId: vscodeComment.commentId, mode: vscodeComment.mode, contextValue: vscodeComment.contextValue, uniqueIdInThread: commentUniqueId, @@ -545,17 +502,16 @@ function convertToModeComment(thread: ExtHostCommentThread, commentController: E userName: vscodeComment.author.name, userIconPath: iconPath, label: vscodeComment.label, - commentReactions: vscodeComment.reactions ? vscodeComment.reactions.map(reaction => convertToReaction(commentController.reactionProvider, reaction)) : undefined + commentReactions: vscodeComment.reactions ? vscodeComment.reactions.map(reaction => convertToReaction(reaction)) : undefined }; } -function convertToReaction(provider: vscode.CommentReactionProvider | undefined, reaction: vscode.CommentReaction): modes.CommentReaction { +function convertToReaction(reaction: vscode.CommentReaction): modes.CommentReaction { return { label: reaction.label, iconPath: reaction.iconPath ? extHostTypeConverter.pathOrURIToURI(reaction.iconPath) : undefined, count: reaction.count, - hasReacted: reaction.hasReacted, - canEdit: provider !== undefined ? !!provider.toggleReaction : false + hasReacted: reaction.authorHasReacted, }; } @@ -564,7 +520,6 @@ function convertFromReaction(reaction: modes.CommentReaction): vscode.CommentRea label: reaction.label || '', count: reaction.count || 0, iconPath: reaction.iconPath ? URI.revive(reaction.iconPath) : '', - hasReacted: reaction.hasReacted, authorHasReacted: reaction.hasReacted || false }; } diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts index 28c771b69f..1f34aff476 100644 --- a/src/vs/workbench/api/node/extHostCLIServer.ts +++ b/src/vs/workbench/api/node/extHostCLIServer.ts @@ -18,6 +18,7 @@ export interface OpenCommandPipeArgs { forceNewWindow?: boolean; diffMode?: boolean; addMode?: boolean; + gotoLineMode?: boolean; forceReuseWindow?: boolean; waitMarkerFilePath?: string; } @@ -93,7 +94,7 @@ export class CLIServer { } private open(data: OpenCommandPipeArgs, res: http.ServerResponse) { - let { fileURIs, folderURIs, forceNewWindow, diffMode, addMode, forceReuseWindow, waitMarkerFilePath } = data; + let { fileURIs, folderURIs, forceNewWindow, diffMode, addMode, forceReuseWindow, gotoLineMode, waitMarkerFilePath } = data; const urisToOpen: IURIToOpen[] = []; if (Array.isArray(folderURIs)) { for (const s of folderURIs) { @@ -125,7 +126,7 @@ export class CLIServer { } if (urisToOpen.length) { const waitMarkerFileURI = waitMarkerFilePath ? URI.file(waitMarkerFilePath) : undefined; - const windowOpenArgs: IOpenSettings = { forceNewWindow, diffMode, addMode, forceReuseWindow, waitMarkerFileURI }; + const windowOpenArgs: IOpenSettings = { forceNewWindow, diffMode, addMode, gotoLineMode, forceReuseWindow, waitMarkerFileURI }; this._commands.executeCommand('_files.windowOpen', urisToOpen, windowOpenArgs); } res.writeHead(200); diff --git a/src/vs/workbench/api/node/extHostRequireInterceptor.ts b/src/vs/workbench/api/node/extHostRequireInterceptor.ts index 3e4a5a958a..fc414e778c 100644 --- a/src/vs/workbench/api/node/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/node/extHostRequireInterceptor.ts @@ -231,23 +231,19 @@ export class OpenNodeModuleFactory implements INodeModuleFactory { if (!this._extensionId) { return; } - /* __GDPR__ - "shimming.open" : { - "extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this._mainThreadTelemerty.$publicLog('shimming.open', { extension: this._extensionId }); + type ShimmingOpenClassification = { + extension: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this._mainThreadTelemerty.$publicLog2<{ extension: string }, ShimmingOpenClassification>('shimming.open', { extension: this._extensionId }); } private sendNoForwardTelemetry(): void { if (!this._extensionId) { return; } - /* __GDPR__ - "shimming.open.call.noForward" : { - "extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this._mainThreadTelemerty.$publicLog('shimming.open.call.noForward', { extension: this._extensionId }); + type ShimmingOpenCallNoForwardClassification = { + extension: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this._mainThreadTelemerty.$publicLog2<{ extension: string }, ShimmingOpenCallNoForwardClassification>('shimming.open.call.noForward', { extension: this._extensionId }); } } diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index e1b1eae86a..da22288d23 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -40,7 +40,7 @@ .monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { content: ''; position: absolute; - left: 11px; + left: calc(50% - 8px); /* 3px (margin) + 5px (padding) = 8px */ top: -5px; border-bottom-width: 5px; border-bottom-style: solid; diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index c8e6f7afcf..24f2d839c6 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -11,10 +11,10 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' // tslint:disable-next-line: import-patterns no-standalone-editor import { IDownloadService } from 'vs/platform/download/common/download'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions'; +import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionType, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IURLHandler, IURLService } from 'vs/platform/url/common/url'; -import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -25,10 +25,8 @@ import { IRecentlyOpened, IRecent, isRecentFile, isRecentFolder } from 'vs/platf import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; -import { IReloadSessionEvent, IExtensionHostDebugService, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { IRemoteConsoleLog } from 'vs/base/common/console'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; // tslint:disable-next-line: import-patterns -import { IExtensionsWorkbenchService, IExtension as IExtension2 } from 'vs/workbench/contrib/extensions/common/extensions'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { addDisposableListener, EventType } from 'vs/base/browser/dom'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; @@ -36,11 +34,12 @@ import { pathsToEditors } from 'vs/workbench/common/editor'; import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; // tslint:disable-next-line: import-patterns import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; //#region Download @@ -58,62 +57,6 @@ registerSingleton(IDownloadService, SimpleDownloadService, true); //#endregion -//#endregion IExtensionsWorkbenchService -export class SimpleExtensionsWorkbenchService implements IExtensionsWorkbenchService { - _serviceBrand: any; - onChange: Event; - local: IExtension2[]; - installed: IExtension2[]; - outdated: IExtension2[]; - queryLocal: any; - queryGallery: any; - canInstall: any; - install: any; - uninstall: any; - installVersion: any; - reinstall: any; - setEnablement: any; - open: any; - checkForUpdates: any; - allowedBadgeProviders: string[]; -} -registerSingleton(IExtensionsWorkbenchService, SimpleExtensionsWorkbenchService, true); -//#endregion - -//#region Extension Management - -//#region Extension Enablement - -export class SimpleExtensionEnablementService implements IExtensionEnablementService { - - _serviceBrand: any; - - readonly onEnablementChanged = Event.None; - - readonly allUserExtensionsDisabled = false; - - getEnablementState(extension: IExtension): EnablementState { - return EnablementState.Enabled; - } - - canChangeEnablement(extension: IExtension): boolean { - return false; - } - - setEnablement(extensions: IExtension[], newState: EnablementState): Promise { - throw new Error('not implemented'); - } - - isEnabled(extension: IExtension): boolean { - return true; - } - -} - -registerSingleton(IExtensionEnablementService, SimpleExtensionEnablementService, true); - -//#endregion - //#region Extension Tips export class SimpleExtensionTipsService implements IExtensionTipsService { @@ -145,7 +88,7 @@ export class SimpleExtensionTipsService implements IExtensionTipsService { } getAllIgnoredRecommendations(): { global: string[]; workspace: string[]; } { - return Object.create(null); + return { global: [], workspace: [] }; } } @@ -296,38 +239,6 @@ export class SimpleMultiExtensionsManagementService implements IExtensionManagem //#endregion -//#region Telemetry - -export class SimpleTelemetryService implements ITelemetryService { - - _serviceBrand: undefined; - - isOptedIn: true; - - publicLog(eventName: string, data?: ITelemetryData) { - return Promise.resolve(undefined); - } - - publicLog2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck) { - return this.publicLog(eventName, data as ITelemetryData); - } - - setEnabled(value: boolean): void { - } - - getTelemetryInfo(): Promise { - return Promise.resolve({ - instanceId: 'someValue.instanceId', - sessionId: 'someValue.sessionId', - machineId: 'someValue.machineId' - }); - } -} - -registerSingleton(ITelemetryService, SimpleTelemetryService); - -//#endregion - //#region Update export class SimpleUpdateService implements IUpdateService { @@ -669,23 +580,19 @@ registerSingleton(IWindowService, SimpleWindowService); //#region ExtensionHostDebugService -export class SimpleExtensionHostDebugService implements IExtensionHostDebugService { - _serviceBrand: any; +export class SimpleExtensionHostDebugService extends ExtensionHostDebugChannelClient { - reload(sessionId: string): void { } - onReload: Event = Event.None; + constructor( + @IRemoteAgentService remoteAgentService: IRemoteAgentService + ) { + const connection = remoteAgentService.getConnection(); - close(sessionId: string): void { } - onClose: Event = Event.None; + if (!connection) { + throw new Error('Missing agent connection'); + } - attachSession(sessionId: string, port: number, subId?: string): void { } - onAttachSession: Event = Event.None; - - logToSession(sessionId: string, log: IRemoteConsoleLog): void { } - onLogToSession: Event = Event.None; - - terminateSession(sessionId: string, subId?: string): void { } - onTerminateSession: Event = Event.None; + super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); + } } registerSingleton(IExtensionHostDebugService, SimpleExtensionHostDebugService); @@ -830,6 +737,53 @@ export class SimpleWindowsService implements IWindowsService { } openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { + + // we pass the "ParsedArgs" as query parameters of the URL + + let newAddress = `${document.location.origin}/?`; + + const f = args['folder-uri']; + if (f) { + let u: URI | undefined; + if (Array.isArray(f)) { + if (f.length > 0) { + u = URI.parse(f[0]); + } + } else { + u = URI.parse(f); + } + if (u) { + newAddress += `folder=${encodeURIComponent(u.path)}`; + } + } + + const ep = args['extensionDevelopmentPath']; + if (ep) { + let u: string | undefined; + if (Array.isArray(ep)) { + if (ep.length > 0) { + u = ep[0]; + } + } else { + u = ep; + } + if (u) { + newAddress += `&edp=${encodeURIComponent(u)}`; + } + } + + const di = args['debugId']; + if (di) { + newAddress += `&di=${encodeURIComponent(di)}`; + } + + const ibe = args['inspect-brk-extensions']; + if (ibe) { + newAddress += `&ibe=${encodeURIComponent(ibe)}`; + } + + window.open(newAddress); + return Promise.resolve(); } diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 8107b86655..55be40be18 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -166,7 +166,7 @@ export class CommentNode extends Disposable { secondaryActions.push(...secondary); } - if (actions.length) { + if (actions.length || secondaryActions.length) { this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { actionViewItemProvider: action => { if (action.id === ToggleReactionsAction.ID) { @@ -318,18 +318,18 @@ export class CommentNode extends Disposable { let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); } else { - let reactionGroup = this.commentService.getReactionGroup(this.owner); - if (reactionGroup && reactionGroup.length) { - let toggleReactionAction = this.createReactionPicker2(reactionGroup || []); - this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); - } + // let reactionGroup = this.commentService.getReactionGroup(this.owner); + // if (reactionGroup && reactionGroup.length) { + // let toggleReactionAction = this.createReactionPicker2(reactionGroup || []); + // this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); + // } } } private createCommentEditor(): void { const container = dom.append(this._commentEditContainer, dom.$('.edit-textarea')); this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions(), this.parentEditor, this.parentThread); - const resource = URI.parse(`comment:commentinput-${this.comment.commentId}-${Date.now()}.md`); + const resource = URI.parse(`comment:commentinput-${this.comment.uniqueIdInThread}-${Date.now()}.md`); this._commentEditorModel = this.modelService.createModel('', this.modeService.createByFilepathOrFirstLine(resource), resource, false); this._commentEditor.setModel(this._commentEditorModel); diff --git a/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts index 6b7aac1862..8cf3d7f6b8 100644 --- a/src/vs/workbench/contrib/comments/browser/commentService.ts +++ b/src/vs/workbench/contrib/comments/browser/commentService.ts @@ -54,7 +54,6 @@ export interface ICommentService { disposeCommentThread(ownerId: string, threadId: string): void; getComments(resource: URI): Promise<(ICommentInfo | null)[]>; getCommentingRanges(resource: URI): Promise; - getReactionGroup(owner: string): CommentReaction[] | undefined; hasReactionHandler(owner: string): boolean; toggleReaction(owner: string, resource: URI, thread: CommentThread, comment: Comment, reaction: CommentReaction): Promise; setActiveCommentThread(commentThread: CommentThread | null): void; @@ -183,22 +182,6 @@ export class CommentService extends Disposable implements ICommentService { } } - getReactionGroup(owner: string): CommentReaction[] | undefined { - const commentProvider = this._commentControls.get(owner); - - if (commentProvider) { - return commentProvider.getReactionGroup(); - } - - const commentController = this._commentControls.get(owner); - - if (commentController) { - return commentController.getReactionGroup(); - } - - return undefined; - } - hasReactionHandler(owner: string): boolean { const commentProvider = this._commentControls.get(owner); diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index 8ddf992e57..a3c5582a75 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -161,14 +161,14 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget // we don't do anything here as we always do the reveal ourselves. } - public reveal(commentId?: string) { + public reveal(commentUniqueId?: number) { if (!this._isExpanded) { this.show({ lineNumber: this._commentThread.range.startLineNumber, column: 1 }, 2); } - if (commentId) { + if (commentUniqueId !== undefined) { let height = this.editor.getLayoutInfo().height; - let matchedNode = this._commentElements.filter(commentNode => commentNode.comment.commentId === commentId); + let matchedNode = this._commentElements.filter(commentNode => commentNode.comment.uniqueIdInThread === commentUniqueId); if (matchedNode && matchedNode.length) { const commentThreadCoords = dom.getDomNodePagePosition(this._commentElements[0].domNode); const commentCoords = dom.getDomNodePagePosition(matchedNode[0].domNode); @@ -247,9 +247,14 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._actionbarWidget.push([...groups, this._collapseAction], { label: false, icon: true }); } + private deleteCommentThread(): void { + this.dispose(); + this.commentService.disposeCommentThread(this.owner, this._commentThread.threadId); + } + public collapse(): Promise { if (this._commentThread.comments && this._commentThread.comments.length === 0) { - this.dispose(); + this.deleteCommentThread(); return Promise.resolve(); } @@ -268,7 +273,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget if (this._isExpanded) { this.hide(); if (!this._commentThread.comments || !this._commentThread.comments.length) { - this.dispose(); + this.deleteCommentThread(); } } else { this.show({ lineNumber: lineNumber, column: 1 }, 2); @@ -284,7 +289,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget let commentElementsToDelIndex: number[] = []; for (let i = 0; i < oldCommentsLen; i++) { let comment = this._commentElements[i].comment; - let newComment = commentThread.comments ? commentThread.comments.filter(c => c.commentId === comment.commentId) : []; + let newComment = commentThread.comments ? commentThread.comments.filter(c => c.uniqueIdInThread === comment.uniqueIdInThread) : []; if (newComment.length) { this._commentElements[i].update(newComment[0]); @@ -304,7 +309,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget let newCommentNodeList: CommentNode[] = []; for (let i = newCommentsLen - 1; i >= 0; i--) { let currentComment = commentThread.comments![i]; - let oldCommentNode = this._commentElements.filter(commentNode => commentNode.comment.commentId === currentComment.commentId); + let oldCommentNode = this._commentElements.filter(commentNode => commentNode.comment.uniqueIdInThread === currentComment.uniqueIdInThread); if (oldCommentNode.length) { oldCommentNode[0].update(currentComment); lastCommentElement = oldCommentNode[0].domNode; @@ -601,13 +606,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._disposables.add(newCommentNode); this._disposables.add(newCommentNode.onDidDelete(deletedNode => { - const deletedNodeId = deletedNode.comment.commentId; - const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.commentId === deletedNodeId); + const deletedNodeId = deletedNode.comment.uniqueIdInThread; + const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === deletedNodeId); if (deletedElementIndex > -1) { this._commentElements.splice(deletedElementIndex, 1); } - const deletedCommentIndex = arrays.firstIndex(this._commentThread.comments!, comment => comment.commentId === deletedNodeId); + const deletedCommentIndex = arrays.firstIndex(this._commentThread.comments!, comment => comment.uniqueIdInThread === deletedNodeId); if (deletedCommentIndex > -1) { this._commentThread.comments!.splice(deletedCommentIndex, 1); } diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 0533918b56..0accf94141 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -247,18 +247,18 @@ export class ReviewController implements IEditorContribution { return editor.getContribution(ID); } - public revealCommentThread(threadId: string, commentId: string, fetchOnceIfNotExist: boolean): void { + public revealCommentThread(threadId: string, commentUniqueId: number, fetchOnceIfNotExist: boolean): void { const commentThreadWidget = this._commentWidgets.filter(widget => widget.commentThread.threadId === threadId); if (commentThreadWidget.length === 1) { - commentThreadWidget[0].reveal(commentId); + commentThreadWidget[0].reveal(commentUniqueId); } else if (fetchOnceIfNotExist) { if (this._computePromise) { this._computePromise.then(_ => { - this.revealCommentThread(threadId, commentId, false); + this.revealCommentThread(threadId, commentUniqueId, false); }); } else { this.beginCompute().then(_ => { - this.revealCommentThread(threadId, commentId, false); + this.revealCommentThread(threadId, commentUniqueId, false); }); } } diff --git a/src/vs/workbench/contrib/comments/browser/commentsPanel.ts b/src/vs/workbench/contrib/comments/browser/commentsPanel.ts index 8491681e7a..a0de87828b 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsPanel.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsPanel.ts @@ -175,7 +175,7 @@ export class CommentsPanel extends Panel { let currentActiveResource = activeEditor ? activeEditor.getResource() : undefined; if (currentActiveResource && currentActiveResource.toString() === element.resource.toString()) { const threadToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].threadId : element.threadId; - const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment.commentId : element.comment.commentId; + const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment.uniqueIdInThread : element.comment.uniqueIdInThread; const control = this.editorService.activeTextEditorWidget; if (threadToReveal && isCodeEditor(control)) { const controller = ReviewController.get(control); @@ -200,7 +200,7 @@ export class CommentsPanel extends Panel { const control = editor.getControl(); if (threadToReveal && isCodeEditor(control)) { const controller = ReviewController.get(control); - controller.revealCommentThread(threadToReveal, commentToReveal.commentId, true); + controller.revealCommentThread(threadToReveal, commentToReveal.uniqueIdInThread, true); } } }); diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index 17a6a1285f..1945492d4a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -23,7 +23,7 @@ export class CommentsDataSource implements IDataSource { return element.id; } if (element instanceof CommentNode) { - return `${element.resource.toString()}-${element.comment.commentId}`; + return `${element.resource.toString()}-${element.comment.uniqueIdInThread}`; } return ''; } diff --git a/src/vs/workbench/contrib/comments/browser/media/delete-dark.svg b/src/vs/workbench/contrib/comments/browser/media/delete-dark.svg deleted file mode 100644 index 75644595d1..0000000000 --- a/src/vs/workbench/contrib/comments/browser/media/delete-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/comments/browser/media/delete-hc.svg b/src/vs/workbench/contrib/comments/browser/media/delete-hc.svg deleted file mode 100644 index 75644595d1..0000000000 --- a/src/vs/workbench/contrib/comments/browser/media/delete-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/comments/browser/media/delete-light.svg b/src/vs/workbench/contrib/comments/browser/media/delete-light.svg deleted file mode 100644 index cf5f28ca35..0000000000 --- a/src/vs/workbench/contrib/comments/browser/media/delete-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/comments/browser/media/edit-dark.svg b/src/vs/workbench/contrib/comments/browser/media/edit-dark.svg deleted file mode 100644 index a72757482b..0000000000 --- a/src/vs/workbench/contrib/comments/browser/media/edit-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/comments/browser/media/edit-hc.svg b/src/vs/workbench/contrib/comments/browser/media/edit-hc.svg deleted file mode 100644 index b507253e44..0000000000 --- a/src/vs/workbench/contrib/comments/browser/media/edit-hc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/comments/browser/media/edit-light.svg b/src/vs/workbench/contrib/comments/browser/media/edit-light.svg deleted file mode 100644 index ae71150c0c..0000000000 --- a/src/vs/workbench/contrib/comments/browser/media/edit-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index c69c769362..959731f185 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -29,10 +29,6 @@ height: 21px; } -.monaco-editor .review-widget .body .review-comment .comment-actions .action-item { - width: 22px; -} - .monaco-editor .review-widget .body .review-comment .comment-title { display: flex; width: 100%; @@ -148,10 +144,6 @@ margin-right: 4px; } -.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label { - display: inline-block; -} - .monaco-editor .review-widget .head .review-actions > .monaco-action-bar .icon.expand-review-action { background-image: url("./close-light.svg"); background-size: 16px; @@ -165,32 +157,6 @@ background-image: url("./close-hc.svg"); } -.monaco-editor .review-widget .body .review-comment .comment-title .icon.edit { - background-image: url("./edit-light.svg"); - background-size: 16px; -} - -.monaco-editor.vs-dark .review-widget .body .review-comment .comment-title .icon.edit { - background-image: url("./edit-dark.svg"); -} - -.monaco-editor.hc-black .review-widget .body .review-comment .comment-title .icon.edit { - background-image: url("./edit-hc.svg"); -} - -.monaco-editor .review-widget .body .review-comment .comment-title .icon.delete { - background-image: url("./delete-light.svg"); - background-size: 16px; -} - -.monaco-editor.vs-dark .review-widget .body .review-comment .comment-title .icon.delete { - background-image: url("./delete-dark.svg"); -} - -.monaco-editor.hc-black .review-widget .body .review-comment .comment-title .icon.delete { - background-image: url("./delete-hc.svg"); -} - .monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.toolbar-toggle-pickReactions { display: none; background-image: url("./reaction-light.svg"); @@ -220,7 +186,6 @@ display: block; height: 16px; line-height: 16px; - min-width: 28px; background-size: 16px; background-position: center center; background-repeat: no-repeat; @@ -433,7 +398,8 @@ height: 100%; } -.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-item { +.monaco-editor .review-widget .action-item { + min-width: 16px; margin-left: 4px; } diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 12698ce8ea..bce4c8a965 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -45,7 +45,7 @@ import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_ import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils'; import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; diff --git a/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts b/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts index bdb528288e..3bc4966f70 100644 --- a/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts @@ -220,12 +220,10 @@ export class ExperimentService extends Disposable implements IExperimentService }); return Promise.all(promises).then(() => { - /* __GDPR__ - "experiments" : { - "experiments" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('experiments', { experiments: this._experiments }); + type ExperimentsClassification = { + experiments: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ experiments: IExperiment[] }, ExperimentsClassification>('experiments', { experiments: this._experiments }); }); }); } diff --git a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts index 44a45adb7f..0c91a2337f 100644 --- a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts +++ b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts @@ -10,9 +10,9 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices'; import { - IExtensionManagementService, DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, - IExtensionEnablementService, ILocalExtension + IExtensionManagementService, DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { Emitter } from 'vs/base/common/event'; import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test'; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index d643c7bbc6..11ae3597c1 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -20,7 +20,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IExtensionManifest, IKeyBinding, IView, IViewContainer, ExtensionType } from 'vs/platform/extensions/common/extensions'; import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; @@ -498,6 +498,13 @@ export class ExtensionEditor extends BaseEditor { })); } + clearInput(): void { + this.contentDisposables.clear(); + this.transientDisposables.clear(); + + super.clearInput(); + } + focus(): void { if (this.activeElement) { this.activeElement.focus(); @@ -621,8 +628,7 @@ export class ExtensionEditor extends BaseEditor { this.renderViewContainers(content, manifest, layout), this.renderViews(content, manifest, layout), this.renderLocalizations(content, manifest, layout), - // {{SQL CARBON EDIT}} - renderDashboardContributions(content, manifest, layout) + renderDashboardContributions(content, manifest, layout) // {{SQL CARBON EDIT}} ]; scrollableContent.scanDomNode(); @@ -860,7 +866,7 @@ export class ExtensionEditor extends BaseEditor { const contributes = manifest.contributes; const colors = contributes && contributes.colors; - if (!colors || !colors.length) { + if (!(colors && colors.length)) { return false; } @@ -943,12 +949,12 @@ export class ExtensionEditor extends BaseEditor { menus[context].forEach(menu => { let command = byId[menu.command]; - if (!command) { + if (command) { + command.menus.push(context); + } else { command = { id: menu.command, title: '', keybindings: [], menus: [context] }; byId[command.id] = command; commands.push(command); - } else { - command.menus.push(context); } }); }); @@ -964,12 +970,12 @@ export class ExtensionEditor extends BaseEditor { let command = byId[rawKeybinding.command]; - if (!command) { + if (command) { + command.keybindings.push(keybinding); + } else { command = { id: rawKeybinding.command, title: '', keybindings: [keybinding], menus: [] }; byId[command.id] = command; commands.push(command); - } else { - command.keybindings.push(keybinding); } }); @@ -1023,12 +1029,12 @@ export class ExtensionEditor extends BaseEditor { grammars.forEach(grammar => { let language = byId[grammar.language]; - if (!language) { + if (language) { + language.hasGrammar = true; + } else { language = { id: grammar.language, name: grammar.language, extensions: [], hasGrammar: true, hasSnippets: false }; byId[language.id] = language; languages.push(language); - } else { - language.hasGrammar = true; } }); @@ -1037,12 +1043,12 @@ export class ExtensionEditor extends BaseEditor { snippets.forEach(snippet => { let language = byId[snippet.language]; - if (!language) { + if (language) { + language.hasSnippets = true; + } else { language = { id: snippet.language, name: snippet.language, extensions: [], hasGrammar: false, hasSnippets: true }; byId[language.id] = language; languages.push(language); - } else { - language.hasSnippets = true; } }); @@ -1084,11 +1090,11 @@ export class ExtensionEditor extends BaseEditor { } const keyBinding = KeybindingParser.parseKeybinding(key || rawKeyBinding.key, OS); - if (!keyBinding) { - return null; - } + if (keyBinding) { + return this.keybindingService.resolveKeybinding(keyBinding)[0]; - return this.keybindingService.resolveKeybinding(keyBinding)[0]; + } + return null; } private loadContents(loadingTask: () => CacheResult): Promise { diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts new file mode 100644 index 0000000000..46983d906e --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -0,0 +1,373 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/extensions'; +import { localize } from 'vs/nls'; +import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ExtensionsLabel, ExtensionsChannelId, PreferencesLabel, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/contrib/output/common/output'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { VIEWLET_ID, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; +import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'; +import { + OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, + ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction, + EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, OpenExtensionsFolderAction, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction +} from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; +import { StatusUpdater, ExtensionsViewlet, MaliciousExtensionChecker, ExtensionsViewletViewsContribution } from 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; +import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { KeymapExtensions } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; +import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { GalleryExtensionsHandler, ExtensionsHandler } from 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { ExtensionActivationProgress } from 'vs/workbench/contrib/extensions/browser/extensionsActivationProgress'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/browser/extensionsDependencyChecker'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +// Singletons +registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); + +Registry.as(OutputExtensions.OutputChannels) + .registerChannel({ id: ExtensionsChannelId, label: ExtensionsLabel, log: false }); + +// Quickopen +Registry.as(Extensions.Quickopen).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + ExtensionsHandler, + ExtensionsHandler.ID, + 'ext ', + undefined, + localize('extensionsCommands', "Manage Extensions"), + true + ) +); + +// Editor +const editorDescriptor = new EditorDescriptor( + ExtensionEditor, + ExtensionEditor.ID, + localize('extension', "Extension") +); + +Registry.as(EditorExtensions.Editors) + .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); + +// Viewlet +const viewletDescriptor = new ViewletDescriptor( + ExtensionsViewlet, + VIEWLET_ID, + localize('extensions', "Extensions"), + 'extensions', + 4 +); + +Registry.as(ViewletExtensions.Viewlets) + .registerViewlet(viewletDescriptor); + +// Global actions +const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); + +const openViewletActionDescriptor = new SyncActionDescriptor(OpenExtensionsViewletAction, OpenExtensionsViewletAction.ID, OpenExtensionsViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_X }); +actionRegistry.registerWorkbenchAction(openViewletActionDescriptor, 'View: Show Extensions', localize('view', "View")); + +const installActionDescriptor = new SyncActionDescriptor(InstallExtensionsAction, InstallExtensionsAction.ID, InstallExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(installActionDescriptor, 'Extensions: Install Extensions', ExtensionsLabel); + +const listOutdatedActionDescriptor = new SyncActionDescriptor(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(listOutdatedActionDescriptor, 'Extensions: Show Outdated Extensions', ExtensionsLabel); + +const recommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(recommendationsActionDescriptor, 'Extensions: Show Recommended Extensions', ExtensionsLabel); + +const keymapRecommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedKeymapExtensionsAction, ShowRecommendedKeymapExtensionsAction.ID, ShowRecommendedKeymapExtensionsAction.SHORT_LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_M) }); +actionRegistry.registerWorkbenchAction(keymapRecommendationsActionDescriptor, 'Preferences: Keymaps', PreferencesLabel); + +const languageExtensionsActionDescriptor = new SyncActionDescriptor(ShowLanguageExtensionsAction, ShowLanguageExtensionsAction.ID, ShowLanguageExtensionsAction.SHORT_LABEL); +actionRegistry.registerWorkbenchAction(languageExtensionsActionDescriptor, 'Preferences: Language Extensions', PreferencesLabel); + +const azureExtensionsActionDescriptor = new SyncActionDescriptor(ShowAzureExtensionsAction, ShowAzureExtensionsAction.ID, ShowAzureExtensionsAction.SHORT_LABEL); +actionRegistry.registerWorkbenchAction(azureExtensionsActionDescriptor, 'Preferences: Azure Extensions', PreferencesLabel); + +const popularActionDescriptor = new SyncActionDescriptor(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(popularActionDescriptor, 'Extensions: Show Popular Extensions', ExtensionsLabel); + +const enabledActionDescriptor = new SyncActionDescriptor(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(enabledActionDescriptor, 'Extensions: Show Enabled Extensions', ExtensionsLabel); + +const installedActionDescriptor = new SyncActionDescriptor(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(installedActionDescriptor, 'Extensions: Show Installed Extensions', ExtensionsLabel); + +const disabledActionDescriptor = new SyncActionDescriptor(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(disabledActionDescriptor, 'Extensions: Show Disabled Extensions', ExtensionsLabel); + +const builtinActionDescriptor = new SyncActionDescriptor(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(builtinActionDescriptor, 'Extensions: Show Built-in Extensions', ExtensionsLabel); + +const updateAllActionDescriptor = new SyncActionDescriptor(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL); +actionRegistry.registerWorkbenchAction(updateAllActionDescriptor, 'Extensions: Update All Extensions', ExtensionsLabel); + +const installVSIXActionDescriptor = new SyncActionDescriptor(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL); +actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: Install from VSIX...', ExtensionsLabel); + +const disableAllAction = new SyncActionDescriptor(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL); +actionRegistry.registerWorkbenchAction(disableAllAction, 'Extensions: Disable All Installed Extensions', ExtensionsLabel); + +const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkpsaceAction, DisableAllWorkpsaceAction.ID, DisableAllWorkpsaceAction.LABEL); +actionRegistry.registerWorkbenchAction(disableAllWorkspaceAction, 'Extensions: Disable All Installed Extensions for this Workspace', ExtensionsLabel); + +const enableAllAction = new SyncActionDescriptor(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL); +actionRegistry.registerWorkbenchAction(enableAllAction, 'Extensions: Enable All Extensions', ExtensionsLabel); + +const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkpsaceAction, EnableAllWorkpsaceAction.ID, EnableAllWorkpsaceAction.LABEL); +actionRegistry.registerWorkbenchAction(enableAllWorkspaceAction, 'Extensions: Enable All Extensions for this Workspace', ExtensionsLabel); + +const checkForUpdatesAction = new SyncActionDescriptor(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL); +actionRegistry.registerWorkbenchAction(checkForUpdatesAction, `Extensions: Check for Extension Updates`, ExtensionsLabel); + +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL), `Extensions: Enable Auto Updating Extensions`, ExtensionsLabel); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL), `Extensions: Disable Auto Updating Extensions`, ExtensionsLabel); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallSpecificVersionOfExtensionAction, InstallSpecificVersionOfExtensionAction.ID, InstallSpecificVersionOfExtensionAction.LABEL), 'Install Specific Version of Extension...', ExtensionsLabel); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReinstallAction, ReinstallAction.ID, ReinstallAction.LABEL), 'Reinstall Extension...', localize('developer', "Developer")); + +Registry.as(ConfigurationExtensions.Configuration) + .registerConfiguration({ + id: 'extensions', + order: 30, + title: localize('extensionsConfigurationTitle', "Extensions"), + type: 'object', + properties: { + 'extensions.autoUpdate': { + type: 'boolean', + description: localize('extensionsAutoUpdate', "When enabled, automatically installs updates for extensions. The updates are fetched from a Microsoft online service."), + default: true, + scope: ConfigurationScope.APPLICATION, + tags: ['usesOnlineServices'] + }, + 'extensions.autoCheckUpdates': { + type: 'boolean', + description: localize('extensionsCheckUpdates', "When enabled, automatically checks extensions for updates. If an extension has an update, it is marked as outdated in the Extensions view. The updates are fetched from a Microsoft online service."), + default: true, + scope: ConfigurationScope.APPLICATION, + tags: ['usesOnlineServices'] + }, + 'extensions.ignoreRecommendations': { + type: 'boolean', + description: localize('extensionsIgnoreRecommendations', "When enabled, the notifications for extension recommendations will not be shown."), + default: false + }, + 'extensions.showRecommendationsOnlyOnDemand': { + type: 'boolean', + description: localize('extensionsShowRecommendationsOnlyOnDemand', "When enabled, recommendations will not be fetched or shown unless specifically requested by the user. Some recommendations are fetched from a Microsoft online service."), + default: false, + tags: ['usesOnlineServices'] + }, + 'extensions.closeExtensionDetailsOnViewChange': { + type: 'boolean', + description: localize('extensionsCloseExtensionDetailsOnViewChange', "When enabled, editors with extension details will be automatically closed upon navigating away from the Extensions View."), + default: false + } + } + }); + +const jsonRegistry = Registry.as(jsonContributionRegistry.Extensions.JSONContribution); +jsonRegistry.registerSchema(ExtensionsConfigurationSchemaId, ExtensionsConfigurationSchema); + +// Register Commands +CommandsRegistry.registerCommand('_extensions.manage', (accessor: ServicesAccessor, extensionId: string) => { + const extensionService = accessor.get(IExtensionsWorkbenchService); + const extension = extensionService.local.filter(e => areSameExtensions(e.identifier, { id: extensionId })); + if (extension.length === 1) { + extensionService.open(extension[0]); + } +}); + +CommandsRegistry.registerCommand('extension.open', (accessor: ServicesAccessor, extensionId: string) => { + const extensionService = accessor.get(IExtensionsWorkbenchService); + + return extensionService.queryGallery({ names: [extensionId], pageSize: 1 }, CancellationToken.None).then(pager => { + if (pager.total !== 1) { + return; + } + + extensionService.open(pager.firstPage[0]); + }); +}); + +CommandsRegistry.registerCommand({ + id: 'workbench.extensions.installExtension', + description: { + description: localize('workbench.extensions.installExtension.description', "Install the given extension"), + args: [ + { + name: localize('workbench.extensions.installExtension.arg.name', "Extension id or VSIX resource uri"), + schema: { + 'type': ['object', 'string'] + } + } + ] + }, + handler: async (accessor, arg: string | UriComponents) => { + const extensionManagementService = accessor.get(IExtensionManagementService); + const extensionGalleryService = accessor.get(IExtensionGalleryService); + try { + if (typeof arg === 'string') { + const extension = await extensionGalleryService.getCompatibleExtension({ id: arg }); + if (extension) { + await extensionManagementService.installFromGallery(extension); + } else { + throw new Error(localize('notFound', "Extension '{0}' not found.", arg)); + } + } else { + const vsix = URI.revive(arg); + await extensionManagementService.install(vsix); + } + } catch (e) { + onUnexpectedError(e); + } + } +}); + +CommandsRegistry.registerCommand({ + id: 'workbench.extensions.uninstallExtension', + description: { + description: localize('workbench.extensions.uninstallExtension.description', "Uninstall the given extension"), + args: [ + { + name: localize('workbench.extensions.uninstallExtension.arg.name', "Id of the extension to uninstall"), + schema: { + 'type': 'string' + } + } + ] + }, + handler: async (accessor, id: string) => { + if (!id) { + throw new Error(localize('id required', "Extension id required.")); + } + const extensionManagementService = accessor.get(IExtensionManagementService); + try { + const installed = await extensionManagementService.getInstalled(ExtensionType.User); + const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id })); + if (!extensionToUninstall) { + return Promise.reject(new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-vscode.csharp.", id))); + } + await extensionManagementService.uninstall(extensionToUninstall, true); + } catch (e) { + onUnexpectedError(e); + } + } +}); + +// File menu registration + +MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { + group: '2_keybindings', + command: { + id: ShowRecommendedKeymapExtensionsAction.ID, + title: localize({ key: 'miOpenKeymapExtensions', comment: ['&& denotes a mnemonic'] }, "&&Keymaps") + }, + order: 2 +}); + +MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '2_keybindings', + command: { + id: ShowRecommendedKeymapExtensionsAction.ID, + title: localize('miOpenKeymapExtensions2', "Keymaps") + }, + order: 2 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { + group: '1_settings', + command: { + id: VIEWLET_ID, + title: localize({ key: 'miPreferencesExtensions', comment: ['&& denotes a mnemonic'] }, "&&Extensions") + }, + order: 3 +}); + +// View menu + +MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { + group: '3_views', + command: { + id: VIEWLET_ID, + title: localize({ key: 'miViewExtensions', comment: ['&& denotes a mnemonic'] }, "E&&xtensions") + }, + order: 5 +}); + +// Global Activity Menu + +MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { + group: '2_configuration', + command: { + id: VIEWLET_ID, + title: localize('showExtensions', "Extensions") + }, + order: 3 +}); + +const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); + +class ExtensionsContributions implements IWorkbenchContribution { + + constructor( + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService + ) { + + const canManageExtensions = extensionManagementServerService.localExtensionManagementServer || extensionManagementServerService.remoteExtensionManagementServer; + + if (canManageExtensions) { + Registry.as(Extensions.Quickopen).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + GalleryExtensionsHandler, + GalleryExtensionsHandler.ID, + 'ext install ', + undefined, + localize('galleryExtensionsCommands', "Install Gallery Extensions"), + true + ) + ); + } + + if (workbenchEnvironmentService.extensionsPath) { + const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); + actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); + } + + } + +} + +workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(ConfigureRecommendedExtensionsCommandsContributor, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 7e0c706a50..ee1807b12d 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -16,7 +16,8 @@ import { dispose, Disposable } from 'vs/base/common/lifecycle'; // {{SQL CARBON EDIT}} import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/contrib/extensions/common/extensions'; import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate'; -import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionsLabel, IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionTipsService, IExtensionRecommendation, IExtensionsConfigContent } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -55,9 +56,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IProductService } from 'vs/platform/product/common/product'; @@ -166,10 +165,10 @@ export class InstallAction extends ExtensionAction { @IOpenerService private readonly openerService: IOpenerService, @IExtensionService private readonly runtimeExtensionService: IExtensionService, @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, - @ILabelService private readonly labelService: ILabelService + @ILabelService private readonly labelService: ILabelService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false); this.update(); @@ -197,12 +196,12 @@ export class InstallAction extends ExtensionAction { this.label = InstallAction.INSTALLING_LABEL; this.tooltip = InstallAction.INSTALLING_LABEL; } else { - if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) { + if (this._manifest && this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { if (isUIExtension(this._manifest, this.productService, this.configurationService)) { this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`; this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`; } else { - const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote"); + const host = this.extensionManagementServerService.remoteExtensionManagementServer.label; this.label = `${InstallAction.INSTALL_LABEL} on ${host}`; this.tooltip = `${InstallAction.INSTALL_LABEL} on ${host}`; } @@ -298,7 +297,6 @@ export class RemoteInstallAction extends ExtensionAction { constructor( @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, @@ -315,10 +313,9 @@ export class RemoteInstallAction extends ExtensionAction { this.tooltip = this.label; return; } - const remoteAuthority = this.environmentService.configuration.remoteAuthority; - if (remoteAuthority) { - const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote"); - this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${host}`; + const remoteServer = this.extensionManagementServerService.remoteExtensionManagementServer; + if (remoteServer) { + this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${remoteServer.label}`; this.tooltip = this.label; return; } @@ -333,7 +330,7 @@ export class RemoteInstallAction extends ExtensionAction { this.updateLabel(); return; } - if (this.environmentService.configuration.remoteAuthority + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer // Installed User Extension && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed // Local Workspace Extension @@ -377,7 +374,6 @@ export class LocalInstallAction extends ExtensionAction { constructor( @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, @@ -407,7 +403,7 @@ export class LocalInstallAction extends ExtensionAction { this.updateLabel(); return; } - if (this.environmentService.configuration.remoteAuthority + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer // Installed User Extension && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed // Remote UI or Language pack Extension @@ -423,7 +419,7 @@ export class LocalInstallAction extends ExtensionAction { } async run(): Promise { - if (!this.installing) { + if (this.extensionManagementServerService.localExtensionManagementServer && !this.installing) { this.installing = true; this.update(); this.extensionsWorkbenchService.open(this.extension); @@ -918,13 +914,15 @@ export class EnableForWorkspaceAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension) { - this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.Disabled || this.extension.enablementState === EnablementState.WorkspaceDisabled) && !!this.extension.local && this.extensionEnablementService.canChangeEnablement(this.extension.local); + if (this.extension && this.extension.local) { + this.enabled = this.extension.state === ExtensionState.Installed + && !this.extensionEnablementService.isEnabled(this.extension.local) + && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.WorkspaceEnabled); + return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledWorkspace); } } @@ -944,12 +942,14 @@ export class EnableGloballyAction extends ExtensionAction { update(): void { this.enabled = false; if (this.extension && this.extension.local) { - this.enabled = this.extension.state === ExtensionState.Installed && this.extension.enablementState === EnablementState.Disabled && this.extensionEnablementService.canChangeEnablement(this.extension.local); + this.enabled = this.extension.state === ExtensionState.Installed + && this.extension.enablementState === EnablementState.DisabledGlobally + && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.Enabled); + return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledGlobally); } } @@ -969,13 +969,15 @@ export class DisableForWorkspaceAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { - this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.Enabled || this.extension.enablementState === EnablementState.WorkspaceEnabled) && !!this.extension.local && this.extensionEnablementService.canChangeEnablement(this.extension.local); + if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { + this.enabled = this.extension.state === ExtensionState.Installed + && (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace) + && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.WorkspaceDisabled); + return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledWorkspace); } } @@ -994,13 +996,15 @@ export class DisableGloballyAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))) { - this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.Enabled || this.extension.enablementState === EnablementState.WorkspaceEnabled) && !!this.extension.local && this.extensionEnablementService.canChangeEnablement(this.extension.local); + if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))) { + this.enabled = this.extension.state === ExtensionState.Installed + && (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace) + && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.Disabled); + return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledGlobally); } } @@ -1082,6 +1086,7 @@ export class CheckForUpdatesAction extends Action { id = CheckForUpdatesAction.ID, label = CheckForUpdatesAction.LABEL, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IViewletService private readonly viewletService: IViewletService, @INotificationService private readonly notificationService: INotificationService ) { @@ -1097,7 +1102,7 @@ export class CheckForUpdatesAction extends Action { let msgAvailableExtensions = outdated.length === 1 ? localize('singleUpdateAvailable', "An extension update is available.") : localize('updatesAvailable', "{0} extension updates are available.", outdated.length); - const disabledExtensionsCount = outdated.filter(ext => ext.enablementState === EnablementState.Disabled || ext.enablementState === EnablementState.WorkspaceDisabled).length; + const disabledExtensionsCount = outdated.filter(ext => ext.local && !this.extensionEnablementService.isEnabled(ext.local)).length; if (disabledExtensionsCount) { if (outdated.length === 1) { msgAvailableExtensions = localize('singleDisabledUpdateAvailable', "An update to an extension which is disabled is available."); @@ -1227,7 +1232,6 @@ export class ReloadAction extends ExtensionAction { @IExtensionService private readonly extensionService: IExtensionService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, ) { @@ -1312,7 +1316,7 @@ export class ReloadAction extends ExtensionAction { this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio return; } - if (this.workbenchEnvironmentService.configuration.remoteAuthority) { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { const uiExtension = isUIExtension(this.extension.local.manifest, this.productService, this.configurationService); // Local Workspace Extension if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) { @@ -1741,8 +1745,10 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action { try { if (extension.local && extension.gallery) { if (isUIExtension(extension.local.manifest, this.productService, this.configurationService)) { - await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery); - return; + if (this.extensionManagementServerService.localExtensionManagementServer) { + await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery); + return; + } } else if (this.extensionManagementServerService.remoteExtensionManagementServer) { await this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery); return; @@ -2547,8 +2553,8 @@ export class StatusLabelAction extends Action implements IExtensionContainer { } if (currentEnablementState !== null) { - const currentlyEnabled = currentEnablementState === EnablementState.Enabled || currentEnablementState === EnablementState.WorkspaceEnabled; - const enabled = this.enablementState === EnablementState.Enabled || this.enablementState === EnablementState.WorkspaceEnabled; + const currentlyEnabled = currentEnablementState === EnablementState.EnabledGlobally || currentEnablementState === EnablementState.EnabledWorkspace; + const enabled = this.enablementState === EnablementState.EnabledGlobally || this.enablementState === EnablementState.EnabledWorkspace; if (!currentlyEnabled && enabled) { return canAddExtension() ? localize('enabled', "Enabled") : null; } @@ -2654,7 +2660,6 @@ export class SystemDisabledWarningAction extends ExtensionAction { @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionService private readonly extensionService: IExtensionService, ) { @@ -2677,8 +2682,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { !this.extension.local || !this.extension.server || !this._runningExtensions || - !this.workbenchEnvironmentService.configuration.remoteAuthority || - !this.extensionManagementServerService.remoteExtensionManagementServer || + !(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) || this.extension.state !== ExtensionState.Installed ) { return; @@ -2687,7 +2691,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = this.extension.server === this.extensionManagementServerService.localExtensionManagementServer - ? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer)) + ? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.extensionManagementServerService.remoteExtensionManagementServer.label) : localize('Install language pack also locally', "Install the language pack extension locally to enable it also there."); } return; @@ -2699,19 +2703,19 @@ export class SystemDisabledWarningAction extends ExtensionAction { if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) { if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; - this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer)); + this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.extensionManagementServerService.remoteExtensionManagementServer.label); return; } if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`; - this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer)); + this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.extensionManagementServerService.remoteExtensionManagementServer.label); return; } } if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) { if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; - this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer)); + this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.extensionManagementServerService.remoteExtensionManagementServer.label); return; } if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) { @@ -2722,12 +2726,6 @@ export class SystemDisabledWarningAction extends ExtensionAction { } } - private getServerLabel(server: IExtensionManagementServer): string { - if (server === this.extensionManagementServerService.remoteExtensionManagementServer) { - return this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote"); - } - return server.label; - } run(): Promise { return Promise.resolve(null); } @@ -2750,11 +2748,11 @@ export class DisableAllAction extends Action { } private update(): void { - this.enabled = this.extensionsWorkbenchService.local.some(e => e.type === ExtensionType.User && (e.enablementState === EnablementState.Enabled || e.enablementState === EnablementState.WorkspaceEnabled) && !!e.local && this.extensionEnablementService.canChangeEnablement(e.local)); + this.enabled = this.extensionsWorkbenchService.local.some(e => e.type === ExtensionType.User && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local)); } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.Disabled); + return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.DisabledGlobally); } } @@ -2767,7 +2765,8 @@ export class DisableAllWorkpsaceAction extends Action { constructor( id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService + @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService ) { super(id, label); this.update(); @@ -2776,11 +2775,11 @@ export class DisableAllWorkpsaceAction extends Action { } private update(): void { - this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => e.type === ExtensionType.User && (e.enablementState === EnablementState.Enabled || e.enablementState === EnablementState.WorkspaceEnabled)); + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => e.type === ExtensionType.User && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local)); } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.WorkspaceDisabled); + return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.DisabledWorkspace); } } @@ -2801,11 +2800,11 @@ export class EnableAllAction extends Action { } private update(): void { - this.enabled = this.extensionsWorkbenchService.local.some(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && (e.enablementState === EnablementState.Disabled || e.enablementState === EnablementState.WorkspaceDisabled)); + this.enabled = this.extensionsWorkbenchService.local.some(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local)); } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.Enabled); + return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.EnabledGlobally); } } @@ -2828,11 +2827,11 @@ export class EnableAllWorkpsaceAction extends Action { } private update(): void { - this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && (e.enablementState === EnablementState.Disabled || e.enablementState === EnablementState.WorkspaceDisabled)); + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local)); } run(): Promise { - return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.WorkspaceEnabled); + return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.EnabledWorkspace); } } @@ -2852,18 +2851,22 @@ export class OpenExtensionsFolderAction extends Action { } run(): Promise { - const extensionsHome = URI.file(this.environmentService.extensionsPath); + if (this.environmentService.extensionsPath) { - return Promise.resolve(this.fileService.resolve(extensionsHome)).then(file => { - let itemToShow: URI; - if (file.children && file.children.length > 0) { - itemToShow = file.children[0].resource; - } else { - itemToShow = extensionsHome; - } + const extensionsHome = URI.file(this.environmentService.extensionsPath); - return this.windowsService.showItemInFolder(itemToShow); - }); + return Promise.resolve(this.fileService.resolve(extensionsHome)).then(file => { + let itemToShow: URI; + if (file.children && file.children.length > 0) { + itemToShow = file.children[0].resource; + } else { + itemToShow = extensionsHome; + } + + return this.windowsService.showItemInFolder(itemToShow); + }); + } + return Promise.resolve(); } } @@ -2909,7 +2912,7 @@ export class InstallVSIXAction extends Action { { label: localize('thirdPartExt.yes', 'Yes'), run: () => { - this.extensionsWorkbenchService.install(vsix).then(extension => { + this.extensionsWorkbenchService.install(URI.file(vsix)).then(extension => { const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local))); const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id) : localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id); @@ -2942,7 +2945,7 @@ export class InstallVSIXAction extends Action { { sticky: true } ); } else { - this.extensionsWorkbenchService.install(vsix).then(extension => { + this.extensionsWorkbenchService.install(URI.file(vsix)).then(extension => { const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local))); const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id) : localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id); @@ -3048,7 +3051,8 @@ export class InstallSpecificVersionOfExtensionAction extends Action { @INotificationService private readonly notificationService: INotificationService, @IWindowService private readonly windowService: IWindowService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IExtensionService private readonly extensionService: IExtensionService + @IExtensionService private readonly extensionService: IExtensionService, + @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, ) { super(id, label); } @@ -3070,7 +3074,7 @@ export class InstallSpecificVersionOfExtensionAction extends Action { } private isEnabled(extension: IExtension): boolean { - return !!extension.gallery && (extension.enablementState === EnablementState.Enabled || extension.enablementState === EnablementState.WorkspaceEnabled); + return !!extension.gallery && !!extension.local && this.extensionEnablementService.isEnabled(extension.local); } private async getExtensionEntries(): Promise<(IQuickPickItem & { extension: IExtension, versions: IGalleryExtensionVersion[] })[]> { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index bd2547ec65..8186007390 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -17,7 +17,7 @@ import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, Malic import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index c23cd2b80c..7b32f72fbf 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -24,7 +24,8 @@ import { ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; -import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions'; @@ -55,8 +56,6 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { ILabelService } from 'vs/platform/label/common/label'; import { MementoObject } from 'vs/workbench/common/memento'; @@ -97,7 +96,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService ) { this.registerViews(); } @@ -118,7 +116,9 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio viewDescriptors.push(this.createOtherRecommendedExtensionsListViewDescriptor()); viewDescriptors.push(this.createWorkspaceRecommendedExtensionsListViewDescriptor()); - viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer)); + if (this.extensionManagementServerService.localExtensionManagementServer) { + viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer)); + } if (this.extensionManagementServerService.remoteExtensionManagementServer) { viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.remoteExtensionManagementServer)); } @@ -187,15 +187,15 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] { const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => { - const serverLabel = this.workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? this.labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label; - if (viewTitle && this.workbenchEnvironmentService.configuration.remoteAuthority) { + const serverLabel = server.label; + if (viewTitle && this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { return `${serverLabel} - ${viewTitle}`; } return viewTitle ? viewTitle : serverLabel; }; const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server); const getOutdatedViewName = (): string => getViewName(localize('outdated', "Outdated"), server); - const onDidChangeServerLabel: EventOf = this.workbenchEnvironmentService.configuration.remoteAuthority ? EventOf.map(this.labelService.onDidChangeFormatters, () => undefined) : EventOf.None; + const onDidChangeServerLabel: EventOf = EventOf.map(this.labelService.onDidChangeFormatters, () => undefined); return [{ id: `extensions.${server.authority}.installed`, get name() { return getInstalledViewName(); }, diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 6fe570965e..ac6af06cb5 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -9,7 +9,8 @@ import { assign } from 'vs/base/common/objects'; import { Event, Emitter } from 'vs/base/common/event'; import { isPromiseCanceledError, getErrorMessage } from 'vs/base/common/errors'; import { PagedModel, IPagedModel, IPager, DelayedPagedModel } from 'vs/base/common/paging'; -import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { SortBy, SortOrder, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServer, IExtensionManagementServerService, IExtensionTipsService, IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts index bae9e387eb..7df5164b5d 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts @@ -9,13 +9,11 @@ import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, Extension import { append, $, addClass } from 'vs/base/browser/dom'; import * as platform from 'vs/base/common/platform'; import { localize } from 'vs/nls'; -import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionTipsService, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ILabelService } from 'vs/platform/label/common/label'; import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { Emitter, Event } from 'vs/base/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -151,8 +149,7 @@ export class TooltipWidget extends ExtensionWidget { private readonly recommendationWidget: RecommendationWidget, private readonly reloadAction: ReloadAction, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, - @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService + @ILabelService private readonly labelService: ILabelService ) { super(); this._register(Event.any( @@ -184,7 +181,7 @@ export class TooltipWidget extends ExtensionWidget { } if (this.extension.local && this.extension.state === ExtensionState.Installed) { if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) { - return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority)); + return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.extension.server.label); } return localize('extension enabled locally', "Extension is enabled locally."); } @@ -281,13 +278,11 @@ export class RemoteBadgeWidget extends ExtensionWidget { render(): void { this.clear(); - if (!this.extension || !this.extension.local || !this.extension.server) { + if (!this.extension || !this.extension.local || !this.extension.server || !(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) || this.extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer) { return; } - if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) { - this.remoteBadge.value = this.instantiationService.createInstance(RemoteBadge, this.tooltip); - append(this.element, this.remoteBadge.value.element); - } + this.remoteBadge.value = this.instantiationService.createInstance(RemoteBadge, this.tooltip); + append(this.element, this.remoteBadge.value.element); } } @@ -299,7 +294,7 @@ class RemoteBadge extends Disposable { private readonly tooltip: boolean, @ILabelService private readonly labelService: ILabelService, @IThemeService private readonly themeService: IThemeService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { super(); this.element = $('div.extension-remote-badge'); @@ -323,8 +318,8 @@ class RemoteBadge extends Disposable { if (this.tooltip) { const updateTitle = () => { - if (this.element) { - this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority)); + if (this.element && this.extensionManagementServerService.remoteExtensionManagementServer) { + this.element.title = localize('remote extension title', "Extension in {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label); } }; this._register(this.labelService.onDidChangeFormatters(() => updateTitle())); diff --git a/src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts similarity index 93% rename from src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index c68696d3e9..c0915495e1 100644 --- a/src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import { Event, Emitter } from 'vs/base/common/event'; import { index, distinct } from 'vs/base/common/arrays'; import { ThrottledDelayer } from 'vs/base/common/async'; @@ -15,8 +15,9 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; // {{SQL CARBON EDIT}} import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, - InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, INSTALL_ERROR_INCOMPATIBLE + InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier, INSTALL_ERROR_INCOMPATIBLE } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -36,6 +37,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IProductService } from 'vs/platform/product/common/product'; +import { asDomUri } from 'vs/base/browser/dom'; // {{SQL CARBON EDIT}} import { ExtensionManagementError } from 'vs/platform/extensionManagement/node/extensionManagementService'; @@ -48,7 +50,7 @@ interface IExtensionStateProvider { class Extension implements IExtension { - public enablementState: EnablementState = EnablementState.Enabled; + public enablementState: EnablementState = EnablementState.EnabledGlobally; constructor( private stateProvider: IExtensionStateProvider, @@ -145,7 +147,7 @@ class Extension implements IExtension { private get localIconUrl(): string | null { if (this.local && this.local.manifest.icon) { - return resources.joinPath(this.local.location, this.local.manifest.icon).toString(); + return asDomUri(resources.joinPath(this.local.location, this.local.manifest.icon)).toString(); } return null; } @@ -162,14 +164,14 @@ class Extension implements IExtension { if (this.type === ExtensionType.System && this.local) { if (this.local.manifest && this.local.manifest.contributes) { if (Array.isArray(this.local.manifest.contributes.themes) && this.local.manifest.contributes.themes.length) { - return require.toUrl('../browser/media/theme-icon.png'); + return require.toUrl('./media/theme-icon.png'); } if (Array.isArray(this.local.manifest.contributes.grammars) && this.local.manifest.contributes.grammars.length) { - return require.toUrl('../browser/media/language-icon.svg'); + return require.toUrl('./media/language-icon.svg'); } } } - return require.toUrl('../browser/media/defaultIcon.png'); + return require.toUrl('./media/defaultIcon.png'); } get repository(): string | undefined { @@ -490,8 +492,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private static readonly SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours _serviceBrand: any; - private readonly localExtensions: Extensions; - private readonly remoteExtensions: Extensions | null; + private readonly localExtensions: Extensions | null = null; + private readonly remoteExtensions: Extensions | null = null; private syncDelayer: ThrottledDelayer; private autoUpdateDelayer: ThrottledDelayer; @@ -519,13 +521,13 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension @IProductService private readonly productService: IProductService ) { super(); - this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext))); - this._register(this.localExtensions.onChange(e => this._onChange.fire(e))); + if (this.extensionManagementServerService.localExtensionManagementServer) { + this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext))); + this._register(this.localExtensions.onChange(e => this._onChange.fire(e))); + } if (this.extensionManagementServerService.remoteExtensionManagementServer) { this.remoteExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.remoteExtensionManagementServer, ext => this.getExtensionState(ext))); this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e))); - } else { - this.remoteExtensions = null; } this.syncDelayer = new ThrottledDelayer(ExtensionsWorkbenchService.SyncPeriod); @@ -560,7 +562,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } get installed(): IExtension[] { - const result = [...this.localExtensions.local]; + const result = []; + if (this.localExtensions) { + result.push(...this.localExtensions.local); + } if (this.remoteExtensions) { result.push(...this.remoteExtensions.local); } @@ -568,7 +573,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } get outdated(): IExtension[] { - const allLocal = [...this.localExtensions.local]; + const allLocal = []; + if (this.localExtensions) { + allLocal.push(...this.localExtensions.local); + } if (this.remoteExtensions) { allLocal.push(...this.remoteExtensions.local); } @@ -577,7 +585,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension async queryLocal(server?: IExtensionManagementServer): Promise { if (server) { - if (this.extensionManagementServerService.localExtensionManagementServer === server) { + if (this.localExtensions && this.extensionManagementServerService.localExtensionManagementServer === server) { return this.localExtensions.queryInstalled(); } if (this.remoteExtensions && this.extensionManagementServerService.remoteExtensionManagementServer === server) { @@ -585,12 +593,12 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } } - await this.localExtensions.queryInstalled(); - if (this.remoteExtensions) { - await Promise.all([this.localExtensions.queryInstalled(), this.remoteExtensions.queryInstalled()]); - } else { + if (this.localExtensions) { await this.localExtensions.queryInstalled(); } + if (this.remoteExtensions) { + await this.remoteExtensions.queryInstalled(); + } return this.local; } @@ -654,7 +662,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set): IExtension { - Promise.all([this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet), this.remoteExtensions ? this.remoteExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false)]) + Promise.all([ + this.localExtensions ? this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false), + this.remoteExtensions ? this.remoteExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false) + ]) .then(result => { if (result[0] || result[1]) { this.eventuallyAutoUpdateExtensions(); @@ -690,7 +701,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private getExtensionState(extension: Extension): ExtensionState { const isInstalling = this.installing.some(i => areSameExtensions(i.identifier, extension.identifier)); if (extension.server) { - const state = (extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.localExtensions : this.remoteExtensions!).getExtensionState(extension); + const state = (extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.localExtensions! : this.remoteExtensions!).getExtensionState(extension); return state === ExtensionState.Uninstalled && isInstalling ? ExtensionState.Installing : state; } else if (isInstalling) { return ExtensionState.Installing; @@ -701,7 +712,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return state; } } - return this.localExtensions.getExtensionState(extension); + if (this.localExtensions) { + return this.localExtensions.getExtensionState(extension); + } + return ExtensionState.Uninstalled; } checkForUpdates(): Promise { @@ -772,20 +786,26 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return false; } - return !!(extension as Extension).gallery; + if (!extension.gallery) { + return false; + } + + if (this.extensionManagementServerService.localExtensionManagementServer || this.extensionManagementServerService.remoteExtensionManagementServer) { + return true; + } + + return false; } - install(extension: string | IExtension): Promise { - // {{SQL CARBON EDIT}} - let extensionPolicy = this.configurationService.getValue(ExtensionsPolicyKey); - - if (typeof extension === 'string') { + install(extension: URI | IExtension): Promise { + let extensionPolicy = this.configurationService.getValue(ExtensionsPolicyKey); // {{SQL CARBON EDIT}} add line + if (extension instanceof URI) { return this.installWithProgress(async () => { // {{SQL CARBON EDIT}} - Wrap async call in try/catch. // This is the error handler when installing local VSIX file. // Prompt the user about the error detail. try { - const { identifier } = await this.extensionService.install(URI.file(extension)); + const { identifier } = await this.extensionService.install(extension); this.checkAndEnableDisabledDependencies(identifier); return this.local.filter(local => areSameExtensions(local.identifier, identifier))[0]; } catch (error) { @@ -924,16 +944,16 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private checkAndEnableDisabledDependencies(extensionIdentifier: IExtensionIdentifier): Promise { const extension = this.local.filter(e => (e.local || e.gallery) && areSameExtensions(extensionIdentifier, e.identifier))[0]; if (extension) { - const disabledDepencies = this.getExtensionsRecursively([extension], this.local, EnablementState.Enabled, { dependencies: true, pack: false }); + const disabledDepencies = this.getExtensionsRecursively([extension], this.local, EnablementState.EnabledGlobally, { dependencies: true, pack: false }); if (disabledDepencies.length) { - return this.setEnablement(disabledDepencies, EnablementState.Enabled); + return this.setEnablement(disabledDepencies, EnablementState.EnabledGlobally); } } return Promise.resolve(); } private promptAndSetEnablement(extensions: IExtension[], enablementState: EnablementState): Promise { - const enable = enablementState === EnablementState.Enabled || enablementState === EnablementState.WorkspaceEnabled; + const enable = enablementState === EnablementState.EnabledGlobally || enablementState === EnablementState.EnabledWorkspace; if (enable) { const allDependenciesAndPackedExtensions = this.getExtensionsRecursively(extensions, this.local, enablementState, { dependencies: true, pack: true }); return this.checkAndSetEnablement(extensions, allDependenciesAndPackedExtensions, enablementState); @@ -948,7 +968,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private checkAndSetEnablement(extensions: IExtension[], otherExtensions: IExtension[], enablementState: EnablementState): Promise { const allExtensions = [...extensions, ...otherExtensions]; - const enable = enablementState === EnablementState.Enabled || enablementState === EnablementState.WorkspaceEnabled; + const enable = enablementState === EnablementState.EnabledGlobally || enablementState === EnablementState.EnabledWorkspace; if (!enable) { for (const extension of extensions) { let dependents = this.getDependentsAfterDisablement(extension, allExtensions, this.local); @@ -973,7 +993,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension if (i.enablementState === enablementState) { return false; } - const enable = enablementState === EnablementState.Enabled || enablementState === EnablementState.WorkspaceEnabled; + const enable = enablementState === EnablementState.EnabledGlobally || enablementState === EnablementState.EnabledWorkspace; return (enable || i.type === ExtensionType.User) // Include all Extensions for enablement and only user extensions for disablement && (options.dependencies || options.pack) && extensions.some(extension => @@ -997,7 +1017,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension if (i === extension) { return false; } - if (i.enablementState === EnablementState.WorkspaceDisabled || i.enablementState === EnablementState.Disabled) { + if (!(i.enablementState === EnablementState.EnabledWorkspace || i.enablementState === EnablementState.EnabledGlobally)) { return false; } if (extensionsToDisable.indexOf(i) !== -1) { @@ -1047,7 +1067,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ] } */ - this.telemetryService.publicLog(enablementState === EnablementState.Enabled || enablementState === EnablementState.WorkspaceEnabled ? 'extension:enable' : 'extension:disable', extensions[i].telemetryData); + this.telemetryService.publicLog(enablementState === EnablementState.EnabledGlobally || enablementState === EnablementState.EnabledWorkspace ? 'extension:enable' : 'extension:disable', extensions[i].telemetryData); } } return changed; diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 6f2e0065df..f55e9ec640 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -7,13 +7,15 @@ import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { IPager } from 'vs/base/common/paging'; -import { IQueryOptions, EnablementState, ILocalExtension, IGalleryExtension, IExtensionIdentifier, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IQueryOptions, ILocalExtension, IGalleryExtension, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { EnablementState, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views'; import { Registry } from 'vs/platform/registry/common/platform'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable } from 'vs/base/common/lifecycle'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionManifest, ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { URI } from 'vs/base/common/uri'; export const VIEWLET_ID = 'workbench.view.extensions'; export const VIEW_CONTAINER: ViewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID); @@ -83,7 +85,7 @@ export interface IExtensionsWorkbenchService { queryGallery(token: CancellationToken): Promise>; queryGallery(options: IQueryOptions, token: CancellationToken): Promise>; canInstall(extension: IExtension): boolean; - install(vsix: string): Promise; + install(vsix: URI): Promise; install(extension: IExtension, promptToInstallDependencies?: boolean): Promise; uninstall(extension: IExtension): Promise; installVersion(extension: IExtension, version: string): Promise; diff --git a/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts b/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts index d227d18ba2..3ca63ad27b 100644 --- a/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts @@ -9,7 +9,8 @@ import { Event } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, IExtensionIdentifier, EnablementState, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IExtensionIdentifier, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -70,7 +71,7 @@ export class KeymapExtensions extends Disposable implements IWorkbenchContributi */ this.telemetryService.publicLog('disableOtherKeymaps', telemetryData); if (confirmed) { - this.extensionEnablementService.setEnablement(oldKeymaps.map(keymap => keymap.local), EnablementState.Disabled); + this.extensionEnablementService.setEnablement(oldKeymaps.map(keymap => keymap.local), EnablementState.DisabledGlobally); } }; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index aae90dbdb6..1b90d598ca 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -9,10 +9,8 @@ import { forEach } from 'vs/base/common/collections'; import { Disposable } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; import * as json from 'vs/base/common/json'; -import { - IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, ExtensionRecommendationReason, EXTENSION_IDENTIFIER_PATTERN, - IExtensionsConfigContent, RecommendationChangeNotification, IExtensionRecommendation, ExtensionRecommendationSource, InstallOperation, ILocalExtension -} from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, EXTENSION_IDENTIFIER_PATTERN, InstallOperation, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionsConfigContent, RecommendationChangeNotification, IExtensionRecommendation, ExtensionRecommendationSource } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITextModel } from 'vs/editor/common/model'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 086d4ee42a..aca125fd1a 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -3,105 +3,33 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!../browser/media/extensions'; import { localize } from 'vs/nls'; -import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IExtensionTipsService, ExtensionsLabel, ExtensionsChannelId, PreferencesLabel, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; - +import { IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/contrib/output/common/output'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -// {{SQL CARBON EDIT}} -import { VIEWLET_ID, IExtensionsWorkbenchService, ExtensionsPolicy } from '../common/extensions'; -import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService'; -import { - OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, - ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction, - EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, OpenExtensionsFolderAction, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction -} from 'vs/workbench/contrib/extensions/browser/extensionsActions'; -import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; -import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; -import { StatusUpdater, ExtensionsViewlet, MaliciousExtensionChecker, ExtensionsViewletViewsContribution } from 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; -import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { KeymapExtensions } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; -import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { GalleryExtensionsHandler, ExtensionsHandler } from 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { RuntimeExtensionsEditor, ShowRuntimeExtensionsAction, IExtensionHostProfileService, DebugExtensionHostAction, StartExtensionHostProfileAction, StopExtensionHostProfileAction, CONTEXT_PROFILE_SESSION_STATE, SaveExtensionHostProfileAction, CONTEXT_EXTENSION_HOST_PROFILE_RECORDED } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; import { EditorInput, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, ActiveEditorContext } from 'vs/workbench/common/editor'; import { ExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-browser/extensionProfileService'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput'; -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { ExtensionActivationProgress } from 'vs/workbench/contrib/extensions/browser/extensionsActivationProgress'; import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/browser/extensionsDependencyChecker'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { ExtensionType } from 'vs/platform/extensions/common/extensions'; // Singletons -registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); registerSingleton(IExtensionTipsService, ExtensionTipsService); registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(ConfigureRecommendedExtensionsCommandsContributor, LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored); -workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting); -workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually); - -Registry.as(OutputExtensions.OutputChannels) - .registerChannel({ id: ExtensionsChannelId, label: ExtensionsLabel, log: false }); - -// Quickopen -Registry.as(Extensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - ExtensionsHandler, - ExtensionsHandler.ID, - 'ext ', - undefined, - localize('extensionsCommands', "Manage Extensions"), - true - ) -); - -Registry.as(Extensions.Quickopen).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - GalleryExtensionsHandler, - GalleryExtensionsHandler.ID, - 'ext install ', - undefined, - localize('galleryExtensionsCommands', "Install Gallery Extensions"), - true - ) -); - -// Editor -const editorDescriptor = new EditorDescriptor( - ExtensionEditor, - ExtensionEditor.ID, - localize('extension', "Extension") -); - -Registry.as(EditorExtensions.Editors) - .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); // Running Extensions Editor @@ -126,159 +54,12 @@ class RuntimeExtensionsInputFactory implements IEditorInputFactory { Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(RuntimeExtensionsInput.ID, RuntimeExtensionsInputFactory); -// Viewlet -const viewletDescriptor = new ViewletDescriptor( - ExtensionsViewlet, - VIEWLET_ID, - localize('extensions', "Extensions"), - 'extensions', - // {{SQL CARBON EDIT}} - 14 -); - -Registry.as(ViewletExtensions.Viewlets) - .registerViewlet(viewletDescriptor); - // Global actions const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -const openViewletActionDescriptor = new SyncActionDescriptor(OpenExtensionsViewletAction, OpenExtensionsViewletAction.ID, OpenExtensionsViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_X }); -actionRegistry.registerWorkbenchAction(openViewletActionDescriptor, 'View: Show Extensions', localize('view', "View")); - -const installActionDescriptor = new SyncActionDescriptor(InstallExtensionsAction, InstallExtensionsAction.ID, InstallExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(installActionDescriptor, 'Extensions: Install Extensions', ExtensionsLabel); - -const listOutdatedActionDescriptor = new SyncActionDescriptor(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(listOutdatedActionDescriptor, 'Extensions: Show Outdated Extensions', ExtensionsLabel); - -const recommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(recommendationsActionDescriptor, 'Extensions: Show Recommended Extensions', ExtensionsLabel); - -const keymapRecommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedKeymapExtensionsAction, ShowRecommendedKeymapExtensionsAction.ID, ShowRecommendedKeymapExtensionsAction.SHORT_LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_M) }); -actionRegistry.registerWorkbenchAction(keymapRecommendationsActionDescriptor, 'Preferences: Keymaps', PreferencesLabel); - -const languageExtensionsActionDescriptor = new SyncActionDescriptor(ShowLanguageExtensionsAction, ShowLanguageExtensionsAction.ID, ShowLanguageExtensionsAction.SHORT_LABEL); -actionRegistry.registerWorkbenchAction(languageExtensionsActionDescriptor, 'Preferences: Language Extensions', PreferencesLabel); - -const azureExtensionsActionDescriptor = new SyncActionDescriptor(ShowAzureExtensionsAction, ShowAzureExtensionsAction.ID, ShowAzureExtensionsAction.SHORT_LABEL); -actionRegistry.registerWorkbenchAction(azureExtensionsActionDescriptor, 'Preferences: Azure Extensions', PreferencesLabel); - -// {{SQL CARBON EDIT}} -// const popularActionDescriptor = new SyncActionDescriptor(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL); -// actionRegistry.registerWorkbenchAction(popularActionDescriptor, 'Extensions: Show Popular Extensions', ExtensionsLabel); - -const enabledActionDescriptor = new SyncActionDescriptor(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(enabledActionDescriptor, 'Extensions: Show Enabled Extensions', ExtensionsLabel); - -const installedActionDescriptor = new SyncActionDescriptor(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(installedActionDescriptor, 'Extensions: Show Installed Extensions', ExtensionsLabel); - -const disabledActionDescriptor = new SyncActionDescriptor(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(disabledActionDescriptor, 'Extensions: Show Disabled Extensions', ExtensionsLabel); - -const builtinActionDescriptor = new SyncActionDescriptor(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(builtinActionDescriptor, 'Extensions: Show Built-in Extensions', ExtensionsLabel); - -const updateAllActionDescriptor = new SyncActionDescriptor(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL); -actionRegistry.registerWorkbenchAction(updateAllActionDescriptor, 'Extensions: Update All Extensions', ExtensionsLabel); - -const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); -actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); - -const installVSIXActionDescriptor = new SyncActionDescriptor(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL); -actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: Install from VSIX...', ExtensionsLabel); - -const disableAllAction = new SyncActionDescriptor(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL); -actionRegistry.registerWorkbenchAction(disableAllAction, 'Extensions: Disable All Installed Extensions', ExtensionsLabel); - -const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkpsaceAction, DisableAllWorkpsaceAction.ID, DisableAllWorkpsaceAction.LABEL); -actionRegistry.registerWorkbenchAction(disableAllWorkspaceAction, 'Extensions: Disable All Installed Extensions for this Workspace', ExtensionsLabel); - -const enableAllAction = new SyncActionDescriptor(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL); -actionRegistry.registerWorkbenchAction(enableAllAction, 'Extensions: Enable All Extensions', ExtensionsLabel); - -const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkpsaceAction, EnableAllWorkpsaceAction.ID, EnableAllWorkpsaceAction.LABEL); -actionRegistry.registerWorkbenchAction(enableAllWorkspaceAction, 'Extensions: Enable All Extensions for this Workspace', ExtensionsLabel); - -const checkForUpdatesAction = new SyncActionDescriptor(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL); -actionRegistry.registerWorkbenchAction(checkForUpdatesAction, `Extensions: Check for Extension Updates`, ExtensionsLabel); - -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL), `Extensions: Enable Auto Updating Extensions`, ExtensionsLabel); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL), `Extensions: Disable Auto Updating Extensions`, ExtensionsLabel); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallSpecificVersionOfExtensionAction, InstallSpecificVersionOfExtensionAction.ID, InstallSpecificVersionOfExtensionAction.LABEL), 'Install Specific Version of Extension...', ExtensionsLabel); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowRuntimeExtensionsAction, ShowRuntimeExtensionsAction.ID, ShowRuntimeExtensionsAction.LABEL), 'Show Running Extensions', localize('developer', "Developer")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReinstallAction, ReinstallAction.ID, ReinstallAction.LABEL), 'Reinstall Extension...', localize('developer', "Developer")); - -Registry.as(ConfigurationExtensions.Configuration) - .registerConfiguration({ - id: 'extensions', - order: 30, - title: localize('extensionsConfigurationTitle', "Extensions"), - type: 'object', - properties: { - 'extensions.autoUpdate': { - type: 'boolean', - description: localize('extensionsAutoUpdate', "When enabled, automatically installs updates for extensions. The updates are fetched from a Microsoft online service."), - default: true, - scope: ConfigurationScope.APPLICATION, - tags: ['usesOnlineServices'] - }, - 'extensions.autoCheckUpdates': { - type: 'boolean', - description: localize('extensionsCheckUpdates', "When enabled, automatically checks extensions for updates. If an extension has an update, it is marked as outdated in the Extensions view. The updates are fetched from a Microsoft online service."), - default: true, - scope: ConfigurationScope.APPLICATION, - tags: ['usesOnlineServices'] - }, - 'extensions.ignoreRecommendations': { - type: 'boolean', - description: localize('extensionsIgnoreRecommendations', "When enabled, the notifications for extension recommendations will not be shown."), - default: false - }, - 'extensions.showRecommendationsOnlyOnDemand': { - type: 'boolean', - description: localize('extensionsShowRecommendationsOnlyOnDemand', "When enabled, recommendations will not be fetched or shown unless specifically requested by the user. Some recommendations are fetched from a Microsoft online service."), - default: false, - tags: ['usesOnlineServices'] - }, - 'extensions.closeExtensionDetailsOnViewChange': { - type: 'boolean', - description: localize('extensionsCloseExtensionDetailsOnViewChange', "When enabled, editors with extension details will be automatically closed upon navigating away from the Extensions View."), - default: false - }, - // {{SQL CARBON EDIT}} - 'extensions.extensionsPolicy': { - type: 'string', - description: localize('extensionsPolicy', "Sets the security policy for downloading extensions."), - scope: ConfigurationScope.APPLICATION, - default: ExtensionsPolicy.allowAll - }, - } - }); - -const jsonRegistry = Registry.as(jsonContributionRegistry.Extensions.JSONContribution); -jsonRegistry.registerSchema(ExtensionsConfigurationSchemaId, ExtensionsConfigurationSchema); // Register Commands -CommandsRegistry.registerCommand('_extensions.manage', (accessor: ServicesAccessor, extensionId: string) => { - const extensionService = accessor.get(IExtensionsWorkbenchService); - const extension = extensionService.local.filter(e => areSameExtensions(e.identifier, { id: extensionId })); - if (extension.length === 1) { - extensionService.open(extension[0]); - } -}); - -CommandsRegistry.registerCommand('extension.open', (accessor: ServicesAccessor, extensionId: string) => { - const extensionService = accessor.get(IExtensionsWorkbenchService); - - return extensionService.queryGallery({ names: [extensionId], pageSize: 1 }, CancellationToken.None).then(pager => { - if (pager.total !== 1) { - return; - } - - extensionService.open(pager.firstPage[0]); - }); -}); CommandsRegistry.registerCommand(DebugExtensionHostAction.ID, (accessor: ServicesAccessor) => { const instantiationService = accessor.get(IInstantiationService); @@ -300,49 +81,6 @@ CommandsRegistry.registerCommand(SaveExtensionHostProfileAction.ID, (accessor: S instantiationService.createInstance(SaveExtensionHostProfileAction, SaveExtensionHostProfileAction.ID, SaveExtensionHostProfileAction.LABEL).run(); }); -// File menu registration - -// {{SQL CARBON EDIT}} - Disable unused menu item -// MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { -// group: '2_keybindings', -// command: { -// id: ShowRecommendedKeymapExtensionsAction.ID, -// title: localize({ key: 'miOpenKeymapExtensions', comment: ['&& denotes a mnemonic'] }, "&&Keymaps") -// }, -// order: 2 -// }); -// {{SQL CARBON EDIT}} - End - -MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '2_keybindings', - command: { - id: ShowRecommendedKeymapExtensionsAction.ID, - title: localize('miOpenKeymapExtensions2', "Keymaps") - }, - order: 2 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { - group: '1_settings', - command: { - id: VIEWLET_ID, - title: localize({ key: 'miPreferencesExtensions', comment: ['&& denotes a mnemonic'] }, "&&Extensions") - }, - order: 3 -}); - -// View menu - -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '3_views', - command: { - id: VIEWLET_ID, - title: localize({ key: 'miViewExtensions', comment: ['&& denotes a mnemonic'] }, "E&&xtensions") - }, - // {{SQL CARBON EDIT}} - Change the order - order: 7 -}); - // Running extensions MenuRegistry.appendMenuItem(MenuId.EditorTitle, { @@ -396,78 +134,4 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { }, group: 'navigation', when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(RuntimeExtensionsEditor.ID)) -}); - -CommandsRegistry.registerCommand({ - id: 'workbench.extensions.installExtension', - description: { - description: localize('workbench.extensions.installExtension.description', "Install the given extension"), - args: [ - { - name: localize('workbench.extensions.installExtension.arg.name', "Extension id or VSIX resource uri"), - schema: { - 'type': ['object', 'string'] - } - } - ] - }, - handler: async (accessor, arg: string | UriComponents) => { - const extensionManagementService = accessor.get(IExtensionManagementService); - const extensionGalleryService = accessor.get(IExtensionGalleryService); - try { - if (typeof arg === 'string') { - const extension = await extensionGalleryService.getCompatibleExtension({ id: arg }); - if (extension) { - await extensionManagementService.installFromGallery(extension); - } else { - throw new Error(localize('notFound', "Extension '{0}' not found.", arg)); - } - } else { - const vsix = URI.revive(arg); - await extensionManagementService.install(vsix); - } - } catch (e) { - onUnexpectedError(e); - } - } -}); - -CommandsRegistry.registerCommand({ - id: 'workbench.extensions.uninstallExtension', - description: { - description: localize('workbench.extensions.uninstallExtension.description', "Uninstall the given extension"), - args: [ - { - name: localize('workbench.extensions.uninstallExtension.arg.name', "Id of the extension to uninstall"), - schema: { - 'type': 'string' - } - } - ] - }, - handler: async (accessor, id: string) => { - if (!id) { - throw new Error(localize('id required', "Extension id required.")); - } - const extensionManagementService = accessor.get(IExtensionManagementService); - try { - const installed = await extensionManagementService.getInstalled(ExtensionType.User); - const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id })); - if (!extensionToUninstall) { - return Promise.reject(new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-vscode.csharp.", id))); - } - await extensionManagementService.uninstall(extensionToUninstall, true); - } catch (e) { - onUnexpectedError(e); - } - } -}); - -MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '2_configuration', - command: { - id: VIEWLET_ID, - title: localize('showExtensions', "Extensions") - }, - order: 3 }); \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index 122c32e31e..9c2ae3c806 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -23,7 +23,7 @@ import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { RunOnceScheduler } from 'vs/base/common/async'; import { clipboard } from 'electron'; -import { EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { writeFile } from 'vs/base/node/pfs'; @@ -420,8 +420,8 @@ export class RuntimeExtensionsEditor extends BaseEditor { actions.push(new Separator()); if (e.element.marketplaceInfo) { - actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.WorkspaceDisabled))); - actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.Disabled))); + actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledWorkspace))); + actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledGlobally))); actions.push(new Separator()); } const state = this._extensionHostProfileService.state; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 67dfcf1463..891fbb0883 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -8,11 +8,12 @@ import { assign } from 'vs/base/common/objects'; import { generateUuid } from 'vs/base/common/uuid'; import { IExtensionsWorkbenchService, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions'; import * as ExtensionsActions from 'vs/workbench/contrib/extensions/browser/extensionsActions'; -import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService'; +import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'; import { - IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService, IExtensionManagementServer + IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService'; @@ -39,7 +40,7 @@ import { ExtensionIdentifier, IExtensionContributions, ExtensionType, IExtension import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ILabelService } from 'vs/platform/label/common/label'; -import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; +import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; import { IProductService } from 'vs/platform/product/common/product'; suite('ExtensionsActions Test', () => { @@ -79,7 +80,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService { private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' }; constructor() { - super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(IConfigurationService), instantiationService.get(IProductService), instantiationService.get(ILogService)); + super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(IConfigurationService), instantiationService.get(IProductService), instantiationService.get(ILogService), instantiationService.get(ILabelService)); } get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; } set localExtensionManagementServer(server: IExtensionManagementServer) { } @@ -601,7 +602,7 @@ suite('ExtensionsActions Test', () => { test('Test EnableForWorkspaceAction when the extension is disabled globally', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -616,7 +617,7 @@ suite('ExtensionsActions Test', () => { test('Test EnableForWorkspaceAction when extension is disabled for workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -631,8 +632,8 @@ suite('ExtensionsActions Test', () => { test('Test EnableForWorkspaceAction when the extension is disabled globally and workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace)) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -665,7 +666,7 @@ suite('ExtensionsActions Test', () => { test('Test EnableGloballyAction when the extension is disabled for workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -680,7 +681,7 @@ suite('ExtensionsActions Test', () => { test('Test EnableGloballyAction when the extension is disabled globally', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -695,8 +696,8 @@ suite('ExtensionsActions Test', () => { test('Test EnableGloballyAction when the extension is disabled in both', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace)) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -729,7 +730,7 @@ suite('ExtensionsActions Test', () => { test('Test EnableDropDownAction when extension is installed and disabled globally', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -744,7 +745,7 @@ suite('ExtensionsActions Test', () => { test('Test EnableDropDownAction when extension is installed and disabled for workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -805,7 +806,7 @@ suite('ExtensionsActions Test', () => { test('Test DisableForWorkspaceAction when the extension is disabled globally', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -820,7 +821,7 @@ suite('ExtensionsActions Test', () => { test('Test DisableForWorkspaceAction when the extension is disabled workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -853,7 +854,7 @@ suite('ExtensionsActions Test', () => { test('Test DisableGloballyAction when the extension is disabled globally', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -868,7 +869,7 @@ suite('ExtensionsActions Test', () => { test('Test DisableGloballyAction when the extension is disabled for workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -913,7 +914,7 @@ suite('ExtensionsActions Test', () => { test('Test DisableDropDownAction when extension is installed and disabled globally', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -928,7 +929,7 @@ suite('ExtensionsActions Test', () => { test('Test DisableDropDownAction when extension is installed and disabled for workspace', () => { const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.WorkspaceDisabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace) .then(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -1200,7 +1201,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running', () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]); const local = aLocalExtension('a', { version: '1.0.1' }); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1228,7 +1229,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); return workbenchService.queryLocal().then(extensions => { testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Disabled) + return workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally) .then(() => testObject.update()) .then(() => { assert.ok(testObject.enabled); @@ -1248,8 +1249,8 @@ suite('ExtensionsActions Test', () => { return workbenchService.queryLocal(). then(extensions => { testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Disabled) - .then(() => workbenchService.setEnablement(extensions[0], EnablementState.Enabled)) + return workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally) + .then(() => workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally)) .then(() => assert.ok(!testObject.enabled)); }); }); @@ -1257,7 +1258,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is enabled when not running', () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]); const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1266,7 +1267,7 @@ suite('ExtensionsActions Test', () => { return workbenchService.queryLocal() .then(extensions => { testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Enabled) + return workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally) .then(() => testObject.update()) .then(() => { assert.ok(testObject.enabled); @@ -1280,7 +1281,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension enablement is toggled when not running', () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]); const local = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1289,8 +1290,8 @@ suite('ExtensionsActions Test', () => { return workbenchService.queryLocal() .then(extensions => { testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Enabled) - .then(() => workbenchService.setEnablement(extensions[0], EnablementState.Disabled)) + return workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally) + .then(() => workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally)) .then(() => assert.ok(!testObject.enabled)); }); }); @@ -1299,7 +1300,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running and enabled', () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]); const local = aLocalExtension('a', { version: '1.0.1' }); - return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally) .then(() => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1312,7 +1313,7 @@ suite('ExtensionsActions Test', () => { const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); installEvent.fire({ identifier: gallery.identifier, gallery }); didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) }); - return workbenchService.setEnablement(extensions[0], EnablementState.Enabled) + return workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally) .then(() => testObject.update()) .then(() => { assert.ok(testObject.enabled); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts index 25e26c24d1..88308a656c 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts @@ -12,8 +12,9 @@ import * as uuid from 'vs/base/common/uuid'; import { mkdirp, rimraf, RimRafMode } from 'vs/base/node/pfs'; import { IExtensionGalleryService, IGalleryExtensionAssets, IGalleryExtension, IExtensionManagementService, - IExtensionEnablementService, DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index 36b770bad3..782af69b54 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -9,11 +9,12 @@ import { generateUuid } from 'vs/base/common/uuid'; import { ExtensionsListView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService'; +import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'; import { - IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension, IQueryOptions, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, IExtensionManagementServerService, EnablementState, ExtensionRecommendationReason, SortBy, IExtensionManagementServer + IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, SortBy } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IExtensionTipsService, ExtensionRecommendationReason } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService'; @@ -40,8 +41,9 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; +import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; import { IProductService } from 'vs/platform/product/common/product'; +import { ILabelService } from 'vs/platform/label/common/label'; suite('ExtensionsListView Tests', () => { @@ -95,7 +97,7 @@ suite('ExtensionsListView Tests', () => { instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService { private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' }; constructor() { - super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(IConfigurationService), instantiationService.get(IProductService), instantiationService.get(ILogService)); + super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(IConfigurationService), instantiationService.get(IProductService), instantiationService.get(ILogService), instantiationService.get(ILabelService)); } get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; } set localExtensionManagementServer(server: IExtensionManagementServer) { } @@ -143,8 +145,8 @@ suite('ExtensionsListView Tests', () => { ]); } }); - await (instantiationService.get(IExtensionEnablementService)).setEnablement([localDisabledTheme], EnablementState.Disabled); - await (instantiationService.get(IExtensionEnablementService)).setEnablement([localDisabledLanguage], EnablementState.Disabled); + await (instantiationService.get(IExtensionEnablementService)).setEnablement([localDisabledTheme], EnablementState.DisabledGlobally); + await (instantiationService.get(IExtensionEnablementService)).setEnablement([localDisabledLanguage], EnablementState.DisabledGlobally); instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); testableView = instantiationService.createInstance(ExtensionsListView, {}); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 78804c6053..2476525146 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -9,11 +9,12 @@ import * as fs from 'fs'; import { assign } from 'vs/base/common/objects'; import { generateUuid } from 'vs/base/common/uuid'; import { IExtensionsWorkbenchService, ExtensionState, AutoCheckUpdatesConfigurationKey, AutoUpdateConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions'; -import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService'; +import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'; import { - IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService + IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService'; @@ -481,86 +482,86 @@ suite('ExtensionsWorkbenchServiceTest', () => { }); test('test uninstalled extensions are always enabled', async () => { - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledWorkspace)) .then(async () => { testObject = await aWorkbenchService(); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); return testObject.queryGallery(CancellationToken.None).then(pagedResponse => { const actual = pagedResponse.firstPage[0]; - assert.equal(actual.enablementState, EnablementState.Enabled); + assert.equal(actual.enablementState, EnablementState.EnabledGlobally); }); }); }); test('test enablement state installed enabled extension', async () => { - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = await aWorkbenchService(); const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.Enabled); + assert.equal(actual.enablementState, EnablementState.EnabledGlobally); }); }); test('test workspace disabled extension', async () => { const extensionA = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('d')], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.WorkspaceDisabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('e')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('d')], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.DisabledWorkspace)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('e')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA]); testObject = await aWorkbenchService(); const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.WorkspaceDisabled); + assert.equal(actual.enablementState, EnablementState.DisabledWorkspace); }); }); test('test globally disabled extension', async () => { const localExtension = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('d')], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('d')], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localExtension]); testObject = await aWorkbenchService(); const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.Disabled); + assert.equal(actual.enablementState, EnablementState.DisabledGlobally); }); }); test('test enablement state is updated for user extensions', async () => { - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.WorkspaceDisabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledWorkspace) .then(() => { const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.WorkspaceDisabled); + assert.equal(actual.enablementState, EnablementState.DisabledWorkspace); }); }); }); test('test enable extension globally when extension is disabled for workspace', async () => { const localExtension = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.WorkspaceDisabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledWorkspace) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localExtension]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Enabled) + return testObject.setEnablement(testObject.local[0], EnablementState.EnabledGlobally) .then(() => { const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.Enabled); + assert.equal(actual.enablementState, EnablementState.EnabledGlobally); }); }); }); @@ -569,10 +570,10 @@ suite('ExtensionsWorkbenchServiceTest', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.Disabled); + assert.equal(actual.enablementState, EnablementState.DisabledGlobally); }); }); @@ -580,25 +581,25 @@ suite('ExtensionsWorkbenchServiceTest', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', {}, { type: ExtensionType.System })]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.Disabled); + assert.equal(actual.enablementState, EnablementState.DisabledGlobally); }); }); test('test enablement state is updated on change from outside', async () => { const localExtension = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localExtension]); testObject = await aWorkbenchService(); - return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledGlobally) .then(() => { const actual = testObject.local[0]; - assert.equal(actual.enablementState, EnablementState.Disabled); + assert.equal(actual.enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -608,17 +609,17 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Disabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Enabled); + assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.EnabledGlobally); }); }); }); @@ -628,17 +629,17 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Disabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Disabled); + assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -648,17 +649,17 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Disabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Disabled); + assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -668,13 +669,13 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[1], EnablementState.Disabled).then(() => assert.fail('Should fail'), error => assert.ok(true)); + return testObject.setEnablement(testObject.local[1], EnablementState.DisabledGlobally).then(() => assert.fail('Should fail'), error => assert.ok(true)); }); }); @@ -683,15 +684,15 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[1], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[1], EnablementState.DisabledGlobally) .then(() => { - assert.equal(testObject.local[1].enablementState, EnablementState.Disabled); + assert.equal(testObject.local[1].enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -701,19 +702,19 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); const target = sinon.spy(); testObject = await aWorkbenchService(); - return testObject.setEnablement([testObject.local[1], testObject.local[0]], EnablementState.Disabled) + return testObject.setEnablement([testObject.local[1], testObject.local[0]], EnablementState.DisabledGlobally) .then(() => { assert.ok(!target.called); - assert.equal(testObject.local[0].enablementState, EnablementState.Disabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Disabled); + assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -723,19 +724,19 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Disabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.DisabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); const target = sinon.spy(); testObject = await aWorkbenchService(); - return testObject.setEnablement([testObject.local[1], testObject.local[0]], EnablementState.Enabled) + return testObject.setEnablement([testObject.local[1], testObject.local[0]], EnablementState.EnabledGlobally) .then(() => { assert.ok(!target.called); - assert.equal(testObject.local[0].enablementState, EnablementState.Enabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Enabled); + assert.equal(testObject.local[0].enablementState, EnablementState.EnabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.EnabledGlobally); }); }); }); @@ -745,16 +746,16 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c', { extensionDependencies: ['pub.b'] }); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Disabled); + assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -764,16 +765,16 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c', { extensionDependencies: ['pub.b'] }); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Disabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.DisabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Disabled); + assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally); }); }); }); @@ -783,14 +784,14 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b', { extensionDependencies: ['pub.a'] }); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => assert.fail('An extension with dependent should not be disabled'), () => null); }); }); @@ -800,16 +801,16 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c', { extensionDependencies: ['pub.b'] }); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) - .then(() => assert.equal(testObject.local[0].enablementState, EnablementState.Disabled)); + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) + .then(() => assert.equal(testObject.local[0].enablementState, EnablementState.DisabledGlobally)); }); }); @@ -818,13 +819,13 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b', { extensionDependencies: ['pub.c'] }); const extensionC = aLocalExtension('c', { extensionDependencies: ['pub.a'] }); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Enabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Enabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.EnabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.EnabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => assert.fail('An extension with dependent should not be disabled'), () => null); }); }); @@ -834,17 +835,17 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Disabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.DisabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Enabled) + return testObject.setEnablement(testObject.local[0], EnablementState.EnabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Enabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Enabled); + assert.equal(testObject.local[0].enablementState, EnablementState.EnabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.EnabledGlobally); }); }); }); @@ -854,18 +855,18 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Enabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Disabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.EnabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.DisabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); const target = sinon.spy(); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Enabled) + return testObject.setEnablement(testObject.local[0], EnablementState.EnabledGlobally) .then(() => { assert.ok(!target.called); - assert.equal(testObject.local[0].enablementState, EnablementState.Enabled); + assert.equal(testObject.local[0].enablementState, EnablementState.EnabledGlobally); }); }); }); @@ -875,19 +876,19 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b'); const extensionC = aLocalExtension('c'); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Disabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.DisabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); const target = sinon.spy(); testObject = await aWorkbenchService(); - return testObject.setEnablement([testObject.local[1], testObject.local[0]], EnablementState.Enabled) + return testObject.setEnablement([testObject.local[1], testObject.local[0]], EnablementState.EnabledGlobally) .then(() => { assert.ok(!target.called); - assert.equal(testObject.local[0].enablementState, EnablementState.Enabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Enabled); + assert.equal(testObject.local[0].enablementState, EnablementState.EnabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.EnabledGlobally); }); }); }); @@ -897,48 +898,48 @@ suite('ExtensionsWorkbenchServiceTest', () => { const extensionB = aLocalExtension('b', { extensionDependencies: ['pub.c'] }); const extensionC = aLocalExtension('c', { extensionDependencies: ['pub.a'] }); - return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.Disabled)) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.Disabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([extensionA], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionB], EnablementState.DisabledGlobally)) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([extensionC], EnablementState.DisabledGlobally)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [extensionA, extensionB, extensionC]); testObject = await aWorkbenchService(); - return testObject.setEnablement(testObject.local[0], EnablementState.Enabled) + return testObject.setEnablement(testObject.local[0], EnablementState.EnabledGlobally) .then(() => { - assert.equal(testObject.local[0].enablementState, EnablementState.Enabled); - assert.equal(testObject.local[1].enablementState, EnablementState.Enabled); - assert.equal(testObject.local[2].enablementState, EnablementState.Enabled); + assert.equal(testObject.local[0].enablementState, EnablementState.EnabledGlobally); + assert.equal(testObject.local[1].enablementState, EnablementState.EnabledGlobally); + assert.equal(testObject.local[2].enablementState, EnablementState.EnabledGlobally); }); }); }); test('test change event is fired when disablement flags are changed', async () => { - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = await aWorkbenchService(); const target = sinon.spy(); testObject.onChange(target); - return testObject.setEnablement(testObject.local[0], EnablementState.Disabled) + return testObject.setEnablement(testObject.local[0], EnablementState.DisabledGlobally) .then(() => assert.ok(target.calledOnce)); }); }); test('test change event is fired when disablement flags are changed from outside', async () => { const localExtension = aLocalExtension('a'); - return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.Disabled) - .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.WorkspaceDisabled)) + return instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('c')], EnablementState.DisabledGlobally) + .then(() => instantiationService.get(IExtensionEnablementService).setEnablement([aLocalExtension('b')], EnablementState.DisabledWorkspace)) .then(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localExtension]); testObject = await aWorkbenchService(); const target = sinon.spy(); testObject.onChange(target); - return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.Disabled) + return instantiationService.get(IExtensionEnablementService).setEnablement([localExtension], EnablementState.DisabledGlobally) .then(() => assert.ok(target.calledOnce)); }); }); diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index 801c4423fa..7680abee36 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -27,7 +27,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; type FormattingEditProvider = DocumentFormattingEditProvider | DocumentRangeFormattingEditProvider; diff --git a/src/vs/workbench/contrib/issue/electron-browser/issueService.ts b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts index 6b6c9a675c..db2754dd32 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issueService.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts @@ -7,7 +7,8 @@ import { IssueReporterStyles, IIssueService, IssueReporterData, ProcessExplorerD import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { textLinkForeground, inputBackground, inputBorder, inputForeground, buttonBackground, buttonHoverBackground, buttonForeground, inputValidationErrorBorder, foreground, inputActiveOptionBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, editorBackground, editorForeground, listHoverBackground, listHoverForeground, listHighlightForeground, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { webFrame } from 'electron'; import { assign } from 'vs/base/common/objects'; import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts index b9260d2989..f1eab6c64d 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts @@ -15,7 +15,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { Disposable } from 'vs/base/common/lifecycle'; import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfiguration } from 'vs/workbench/contrib/preferences/common/preferences'; import { IRequestService, asJson } from 'vs/platform/request/common/request'; -import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 8c669d64db..a91ee70fed 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -70,6 +70,10 @@ function getExcludeDisplayValue(element: SettingsTreeSettingElement): IListDataI } function getListDisplayValue(element: SettingsTreeSettingElement): IListDataItem[] { + if (!element.value || !isArray(element.value)) { + return []; + } + return element.value.map((key: string) => { return { value: key diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index f13a5961b5..cf33ff57a6 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -168,8 +168,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private static readonly IgnoreTask010DonotShowAgain_key = 'workbench.tasks.ignoreTask010Shown'; private static CustomizationTelemetryEventName: string = 'taskService.customize'; - public static TemplateTelemetryEventName: string = 'taskService.template'; - public _serviceBrand: any; public static OutputChannelId: string = 'tasks'; public static OutputChannelLabel: string = nls.localize('tasks', "Tasks"); @@ -2057,14 +2055,16 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); } configFileCreated = true; - /* __GDPR__ - "taskService.template" : { - "templateId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "autoDetect" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ + type TaskServiceTemplateClassification = { + templateId?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + autoDetect: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type TaskServiceEvent = { + templateId?: string; + autoDetect: boolean; + }; return this.textFileService.create(resource, content).then((result): URI => { - this.telemetryService.publicLog(AbstractTaskService.TemplateTelemetryEventName, { + this.telemetryService.publicLog2('taskService.template', { templateId: selection.id, autoDetect: selection.autoDetect }); diff --git a/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts b/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts index 8933ec35c7..e55fed1c53 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as Objects from 'vs/base/common/objects'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import { IStringDictionary } from 'vs/base/common/collections'; import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ITaskSystem } from 'vs/workbench/contrib/tasks/common/taskSystem'; diff --git a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts index 219d3e0fbb..45be818320 100644 --- a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts +++ b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts @@ -5,7 +5,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { LifecyclePhase, ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; @@ -39,27 +39,41 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr const { filesToOpenOrCreate, filesToDiff } = environmentService.configuration; const activeViewlet = viewletService.getActiveViewlet(); - /* __GDPR__ - "workspaceLoad" : { - "userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToOpenOrCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" }, - "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - telemetryService.publicLog('workspaceLoad', { + type WindowSizeFragment = { + innerHeight: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + innerWidth: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + outerHeight: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + outerWidth: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WorkspaceLoadClassification = { + userAgent: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + emptyWorkbench: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + windowSize: WindowSizeFragment; + 'workbench.filesToOpenOrCreate': { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + 'workbench.filesToDiff': { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + customKeybindingsCount: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + theme: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + language: { classification: 'SystemMetaData', purpose: 'BusinessInsight' }; + pinnedViewlets: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + restoredViewlet?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + restoredEditors: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + startupKind: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WorkspaceLoadEvent = { + userAgent: string; + windowSize: { innerHeight: number, innerWidth: number, outerHeight: number, outerWidth: number }; + emptyWorkbench: boolean; + 'workbench.filesToOpenOrCreate': number; + 'workbench.filesToDiff': number; + customKeybindingsCount: number; + theme: string; + language: string; + pinnedViewlets: string[]; + restoredViewlet?: string; + restoredEditors: number; + startupKind: StartupKind; + }; + telemetryService.publicLog2('workspaceLoad', { userAgent: navigator.userAgent, windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, emptyWorkbench: contextService.getWorkbenchState() === WorkbenchState.EMPTY, diff --git a/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts index 35fc13a87c..714239b4de 100644 --- a/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts @@ -48,7 +48,7 @@ function renderBody( export class ReleaseNotesManager { - private _releaseNotesCache: { [version: string]: Promise; } = Object.create(null); + private readonly _releaseNotesCache = new Map>(); private _currentReleaseNotes: WebviewEditorInput | undefined = undefined; private _lastText: string | undefined; @@ -71,7 +71,7 @@ export class ReleaseNotesManager { } const html = await this.renderBody(this._lastText); if (this._currentReleaseNotes) { - this._currentReleaseNotes.html = html; + this._currentReleaseNotes.webview.html = html; } }); } @@ -88,7 +88,7 @@ export class ReleaseNotesManager { const activeControl = this._editorService.activeControl; if (this._currentReleaseNotes) { this._currentReleaseNotes.setName(title); - this._currentReleaseNotes.html = html; + this._currentReleaseNotes.webview.html = html; this._webviewEditorService.revealWebview(this._currentReleaseNotes, activeControl ? activeControl.group : this._editorGroupService.activeGroup, false); } else { this._currentReleaseNotes = this._webviewEditorService.createWebview( @@ -103,17 +103,17 @@ export class ReleaseNotesManager { URI.parse(require.toUrl('./media')) ] }, - undefined, { - onDidClickLink: uri => this.onDidClickLink(uri), - onDispose: () => { this._currentReleaseNotes = undefined; } - }); + undefined); + + this._currentReleaseNotes.webview.onDidClickLink(uri => this.onDidClickLink(uri)); + this._currentReleaseNotes.onDispose(() => { this._currentReleaseNotes = undefined; }); const iconPath = URI.parse(require.toUrl('./media/code-icon.svg')); this._currentReleaseNotes.iconPath = { light: iconPath, dark: iconPath }; - this._currentReleaseNotes.html = html; + this._currentReleaseNotes.webview.html = html; } return true; @@ -162,8 +162,8 @@ export class ReleaseNotesManager { .replace(/kbstyle\(([^\)]+)\)/gi, kbstyle); }; - if (!this._releaseNotesCache[version]) { - this._releaseNotesCache[version] = this._requestService.request({ url }, CancellationToken.None) + if (!this._releaseNotesCache.has(version)) { + this._releaseNotesCache.set(version, this._requestService.request({ url }, CancellationToken.None) .then(asText) .then(text => { if (!text || !/^#\s/.test(text)) { // release notes always starts with `#` followed by whitespace @@ -172,10 +172,10 @@ export class ReleaseNotesManager { return Promise.resolve(text); }) - .then(text => patchKeybindings(text)); + .then(text => patchKeybindings(text))); } - return this._releaseNotesCache[version]; + return this._releaseNotesCache.get(version)!; } private onDidClickLink(uri: URI) { diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts index 8105c3b537..0a20efa4a0 100644 --- a/src/vs/workbench/contrib/update/electron-browser/update.ts +++ b/src/vs/workbench/contrib/update/electron-browser/update.ts @@ -17,7 +17,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IUpdateService, State as UpdateState, StateType, IUpdate } from 'vs/platform/update/common/update'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { INotificationService, INotificationHandle, Severity } from 'vs/platform/notification/common/notification'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts index 18aecf082c..cb97cb4537 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts @@ -7,31 +7,27 @@ import * as DOM from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorOptions } from 'vs/workbench/common/editor'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; -import { IWebviewService, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview } from 'vs/workbench/contrib/webview/common/webview'; +import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; - export class WebviewEditor extends BaseEditor { public static readonly ID = 'WebviewEditor'; - private _webview: Webview | undefined; + private readonly _scopedContextKeyService = this._register(new MutableDisposable()); private _findWidgetVisible: IContextKey; - private _editorFrame: HTMLElement; + private _editorFrame?: HTMLElement; private _content?: HTMLElement; - private _webviewContent: HTMLElement | undefined; private readonly _webviewFocusTrackerDisposables = this._register(new DisposableStore()); private readonly _onFocusWindowHandler = this._register(new MutableDisposable()); @@ -39,22 +35,21 @@ export class WebviewEditor extends BaseEditor { private readonly _onDidFocusWebview = this._register(new Emitter()); public get onDidFocus(): Event { return this._onDidFocusWebview.event; } - private _pendingMessages: any[] = []; - constructor( @ITelemetryService telemetryService: ITelemetryService, @IThemeService themeService: IThemeService, - @IContextKeyService private _contextKeyService: IContextKeyService, - @IWebviewService private readonly _webviewService: IWebviewService, - @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IEditorService private readonly _editorService: IEditorService, @IWindowService private readonly _windowService: IWindowService, @IStorageService storageService: IStorageService ) { super(WebviewEditor.ID, telemetryService, themeService, storageService); - if (_contextKeyService) { - this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(_contextKeyService); - } + + this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(_contextKeyService); + } + + public get isWebviewEditor() { + return true; } protected createEditor(parent: HTMLElement): void { @@ -63,58 +58,25 @@ export class WebviewEditor extends BaseEditor { parent.appendChild(this._content); } - private doUpdateContainer() { - const webviewContainer = this.input && (this.input as WebviewEditorInput).container; - if (webviewContainer && webviewContainer.parentElement) { - const frameRect = this._editorFrame.getBoundingClientRect(); - const containerRect = webviewContainer.parentElement.getBoundingClientRect(); - - webviewContainer.style.position = 'absolute'; - webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; - webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; - webviewContainer.style.width = `${frameRect.width}px`; - webviewContainer.style.height = `${frameRect.height}px`; - } - } - public dispose(): void { - this._pendingMessages = []; - - // Let the editor input dispose of the webview. - this._webview = undefined; - this._webviewContent = undefined; - - if (this._content && this._content.parentElement) { - this._content.parentElement.removeChild(this._content); + if (this._content) { + this._content.remove(); this._content = undefined; } super.dispose(); } - public sendMessage(data: any): void { - if (this._webview) { - this._webview.sendMessage(data); - } else { - this._pendingMessages.push(data); - } - } public showFind() { - if (this._webview) { - this._webview.showFind(); + this.withWebview(webview => { + webview.showFind(); this._findWidgetVisible.set(true); - } + }); } public hideFind() { this._findWidgetVisible.reset(); - if (this._webview) { - this._webview.hideFind(); - } - } - - public get isWebviewEditor() { - return true; + this.withWebview(webview => webview.hideFind()); } public reload() { @@ -122,16 +84,15 @@ export class WebviewEditor extends BaseEditor { } public layout(_dimension: DOM.Dimension): void { - this.withWebview(webview => { - this.doUpdateContainer(); - webview.layout(); - }); + if (this.input && this.input instanceof WebviewEditorInput) { + this.synchronizeWebviewContainerDimensions(this.input.webview); + this.input.webview.layout(); + } } public focus(): void { super.focus(); if (!this._onFocusWindowHandler.value) { - // Make sure we restore focus when switching back to a VS Code window this._onFocusWindowHandler.value = this._windowService.onDidChangeFocus(focused => { if (focused && this._editorService.activeControl === this) { @@ -143,29 +104,20 @@ export class WebviewEditor extends BaseEditor { } public withWebview(f: (element: Webview) => void): void { - if (this._webview) { - f(this._webview); + if (this.input && this.input instanceof WebviewEditorInput) { + f(this.input.webview); } } protected setEditorVisible(visible: boolean, group: IEditorGroup): void { - if (this.input && this.input instanceof WebviewEditorInput) { + const webview = this.input && (this.input as WebviewEditorInput).webview; + if (webview) { if (visible) { - this.input.claimWebview(this); + webview.claim(this); } else { - this.input.releaseWebview(this); - } - - this.updateWebview(this.input as WebviewEditorInput); - } - - if (this._webviewContent) { - if (visible) { - this._webviewContent.style.visibility = 'visible'; - this.doUpdateContainer(); - } else { - this._webviewContent.style.visibility = 'hidden'; + webview.release(this); } + this.claimWebview(this.input as WebviewEditorInput); } super.setEditorVisible(visible, group); @@ -173,115 +125,69 @@ export class WebviewEditor extends BaseEditor { public clearInput() { if (this.input && this.input instanceof WebviewEditorInput) { - this.input.releaseWebview(this); + this.input.webview.release(this); } - this._webview = undefined; - this._webviewContent = undefined; - this._pendingMessages = []; - super.clearInput(); } - setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise { - if (this.input) { - (this.input as WebviewEditorInput).releaseWebview(this); - this._webview = undefined; - this._webviewContent = undefined; + public async setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise { + if (this.input && this.input instanceof WebviewEditorInput) { + this.input.webview.release(this); } - this._pendingMessages = []; - return super.setInput(input, options, token) - .then(() => input.resolve()) - .then(() => { - if (token.isCancellationRequested) { - return; - } - if (this.group) { - input.updateGroup(this.group.id); - } - this.updateWebview(input); - }); + + await super.setInput(input, options, token); + await input.resolve(); + if (token.isCancellationRequested) { + return; + } + + if (this.group) { + input.updateGroup(this.group.id); + } + + this.claimWebview(input); } - private updateWebview(input: WebviewEditorInput) { - const webview = this.getWebview(input); - input.claimWebview(this); - webview.update(input.html, { - allowScripts: input.options.enableScripts, - localResourceRoots: input.options.localResourceRoots || this.getDefaultLocalResourceRoots(), - portMappings: input.options.portMapping, - }, !!input.options.retainContextWhenHidden); + private claimWebview(input: WebviewEditorInput): void { + input.webview.claim(this); - if (this._webviewContent) { - this._webviewContent.style.visibility = 'visible'; + if (input.webview.options.enableFindWidget) { + this._scopedContextKeyService.value = this._contextKeyService.createScoped(input.webview.container); + this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._scopedContextKeyService.value); } - this.doUpdateContainer(); + if (this._content) { + this._content.setAttribute('aria-flowto', input.webview.container.id); + } + + this.synchronizeWebviewContainerDimensions(input.webview); + this.trackFocus(input.webview); } - private getDefaultLocalResourceRoots(): URI[] { - const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri); - const extension = (this.input as WebviewEditorInput).extension; - if (extension) { - rootPaths.push(extension.location); + private synchronizeWebviewContainerDimensions(webview: WebviewEditorOverlay) { + const webviewContainer = webview.container; + if (webviewContainer && webviewContainer.parentElement && this._editorFrame) { + const frameRect = this._editorFrame.getBoundingClientRect(); + const containerRect = webviewContainer.parentElement.getBoundingClientRect(); + + webviewContainer.style.position = 'absolute'; + webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; + webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; + webviewContainer.style.width = `${frameRect.width}px`; + webviewContainer.style.height = `${frameRect.height}px`; } - return rootPaths; } - private getWebview(input: WebviewEditorInput): Webview { - if (this._webview) { - return this._webview; - } - - this._webviewContent = input.container; - - if (input.webview) { - this._webview = input.webview; - } else { - if (input.options.enableFindWidget) { - this._contextKeyService = this._register(this._contextKeyService.createScoped(this._webviewContent)); - this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); - } - - this._webview = this._webviewService.createWebview(input.id, - { - allowSvgs: true, - extension: input.extension, - enableFindWidget: input.options.enableFindWidget - }, {}); - this._webview.mountTo(this._webviewContent); - input.webview = this._webview; - - if (input.options.tryRestoreScrollPosition) { - this._webview.initialScrollProgress = input.scrollYPercentage; - } - - this._webview.state = input.state ? input.state.state : undefined; - - this._content!.setAttribute('aria-flowto', this._webviewContent.id); - - this.doUpdateContainer(); - } - - for (const message of this._pendingMessages) { - this._webview.sendMessage(message); - } - this._pendingMessages = []; - - this.trackFocus(); - - return this._webview; - } - - private trackFocus() { + private trackFocus(webview: WebviewEditorOverlay): void { this._webviewFocusTrackerDisposables.clear(); // Track focus in webview content - const webviewContentFocusTracker = DOM.trackFocus(this._webviewContent!); + const webviewContentFocusTracker = DOM.trackFocus(webview.container); this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker); this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); // Track focus in webview element - this._webviewFocusTrackerDisposables.add(this._webview!.onDidFocus(() => this._onDidFocusWebview.fire())); + this._webviewFocusTrackerDisposables.add(webview.onDidFocus(() => this._onDidFocusWebview.fire())); } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index 09a74f1ad7..3841104125 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -4,15 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; import { memoize } from 'vs/base/common/decorators'; -import { Emitter } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor'; -import { Webview, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; -import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; -import { WebviewEvents, WebviewInputOptions } from './webviewEditorService'; +import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; class WebviewIconsManager { private readonly _icons = new Map(); @@ -53,77 +49,38 @@ class WebviewIconsManager { } } -export class WebviewEditorInput extends EditorInput { - - private readonly iconsManager = new WebviewIconsManager(); +export class WebviewEditorInput extends EditorInput { public static readonly typeId = 'workbench.editors.webviewInput'; + private static readonly iconsManager = new WebviewIconsManager(); + private _name: string; private _iconPath?: { light: URI, dark: URI }; - private _options: WebviewInputOptions; - private _html: string = ''; - private _currentWebviewHtml: string = ''; - public _events: WebviewEvents | undefined; - private _container?: HTMLElement; - private _webview?: Webview; - private _webviewOwner: any; - private readonly _webviewDisposables = this._register(new DisposableStore()); private _group?: GroupIdentifier; - private _scrollYPercentage: number = 0; - private _state: State; - - public readonly extension?: { - readonly location: URI; - readonly id: ExtensionIdentifier; - }; constructor( public readonly id: string, public readonly viewType: string, name: string, - options: WebviewInputOptions, - state: State, - events: WebviewEvents, - extension: undefined | { + public readonly extension: undefined | { readonly location: URI; readonly id: ExtensionIdentifier; }, - @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, + public readonly webview: WebviewEditorOverlay, ) { super(); this._name = name; - this._options = options; - this._events = events; - this._state = state; this.extension = extension; + + this._register(webview); // The input owns this webview } public getTypeId(): string { return WebviewEditorInput.typeId; } - private readonly _onDidChangeIcon = this._register(new Emitter()); - public readonly onDidChangeIcon = this._onDidChangeIcon.event; - - public dispose() { - this.disposeWebview(); - - if (this._container) { - this._container.remove(); - this._container = undefined; - } - - if (this._events && this._events.onDispose) { - this._events.onDispose(); - } - this._events = undefined; - - this._webview = undefined; - super.dispose(); - } - public getResource(): URI { return URI.from({ scheme: 'webview-panel', @@ -154,7 +111,7 @@ export class WebviewEditorInput extends EditorInput { public set iconPath(value: { light: URI, dark: URI } | undefined) { this._iconPath = value; - this.iconsManager.setIcons(this.id, value); + WebviewEditorInput.iconsManager.setIcons(this.id, value); } public matches(other: IEditorInput): boolean { @@ -165,145 +122,19 @@ export class WebviewEditorInput extends EditorInput { return this._group; } - public get html(): string { - return this._html; - } - - public set html(value: string) { - if (value === this._currentWebviewHtml) { - return; - } - - this._html = value; - - if (this._webview) { - this._webview.html = value; - this._currentWebviewHtml = value; - } - } - - public get state(): State { - return this._state; - } - - public set state(value: State) { - this._state = value; - } - - public get options(): WebviewInputOptions { - return this._options; - } - - public setOptions(value: WebviewOptions) { - this._options = { - ...this._options, - ...value - }; - - if (this._webview) { - this._webview.options = { - allowScripts: this._options.enableScripts, - localResourceRoots: this._options.localResourceRoots, - portMappings: this._options.portMapping, - }; - } - } - - public resolve(): Promise { - return Promise.resolve(new EditorModel()); + public async resolve(): Promise { + return new EditorModel(); } public supportsSplitEditor() { return false; } - public get container(): HTMLElement { - if (!this._container) { - this._container = document.createElement('div'); - this._container.id = `webview-${this.id}`; - const part = this._layoutService.getContainer(Parts.EDITOR_PART); - part.appendChild(this._container); - } - return this._container; - } - - public get webview(): Webview | undefined { - return this._webview; - } - - public set webview(value: Webview | undefined) { - this._webviewDisposables.clear(); - - this._webview = value; - if (!this._webview) { - return; - } - - this._webview.onDidClickLink(link => { - if (this._events && this._events.onDidClickLink) { - this._events.onDidClickLink(link, this._options); - } - }, null, this._webviewDisposables); - - this._webview.onMessage(message => { - if (this._events && this._events.onMessage) { - this._events.onMessage(message); - } - }, null, this._webviewDisposables); - - this._webview.onDidScroll(message => { - this._scrollYPercentage = message.scrollYPercentage; - }, null, this._webviewDisposables); - - this._webview.onDidUpdateState(newState => { - if (this._events && this._events.onDidUpdateWebviewState) { - this._events.onDidUpdateWebviewState(newState); - } - }, null, this._webviewDisposables); - } - - public get scrollYPercentage() { - return this._scrollYPercentage; - } - - public claimWebview(owner: any) { - this._webviewOwner = owner; - } - - public releaseWebview(owner: any) { - if (this._webviewOwner === owner) { - this._webviewOwner = undefined; - if (this._options.retainContextWhenHidden && this._container) { - this._container.style.visibility = 'hidden'; - } else { - this.disposeWebview(); - } - } - } - - public disposeWebview() { - // The input owns the webview and its parent - if (this._webview) { - this._webview.dispose(); - this._webview = undefined; - } - - this._webviewDisposables.clear(); - this._webviewOwner = undefined; - - if (this._container) { - this._container.style.visibility = 'hidden'; - } - - this._currentWebviewHtml = ''; - } - public updateGroup(group: GroupIdentifier): void { this._group = group; } } - export class RevivedWebviewEditorInput extends WebviewEditorInput { private _revived: boolean = false; @@ -311,17 +142,14 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput { id: string, viewType: string, name: string, - options: WebviewInputOptions, - state: any, - events: WebviewEvents, extension: undefined | { readonly location: URI; readonly id: ExtensionIdentifier }, private readonly reviver: (input: WebviewEditorInput) => Promise, - @IWorkbenchLayoutService partService: IWorkbenchLayoutService, + webview: WebviewEditorOverlay, ) { - super(id, viewType, name, options, state, events, extension, partService); + super(id, viewType, name, extension, webview); } public async resolve(): Promise { diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts index 1494af9704..34ddf4fa33 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts @@ -45,10 +45,10 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { const data: SerializedWebview = { viewType: input.viewType, title: input.getName(), - options: input.options, + options: input.webview.options, extensionLocation: input.extension ? input.extension.location : undefined, extensionId: input.extension && input.extension.id ? input.extension.id.value : undefined, - state: input.state, + state: input.webview.state, iconPath: input.iconPath ? { light: input.iconPath.light, dark: input.iconPath.dark, } : undefined, group: input.group }; @@ -68,12 +68,15 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { const extensionLocation = reviveUri(data.extensionLocation); const extensionId = data.extensionId ? new ExtensionIdentifier(data.extensionId) : undefined; const iconPath = reviveIconPath(data.iconPath); - return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, iconPath, data.state, data.options, extensionLocation ? { + const state = reviveState(data.state); + + return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, iconPath, state, data.options, extensionLocation ? { location: extensionLocation, id: extensionId } : undefined, data.group); } } + function reviveIconPath(data: SerializedIconPath | undefined) { if (!data) { return undefined; @@ -98,3 +101,21 @@ function reviveUri(data: string | UriComponents | undefined): URI | undefined { return undefined; } } + + +function reviveState(state: unknown | undefined): undefined | string { + if (!state) { + return undefined; + } + + if (typeof state === 'string') { + return state; + } + + // Likely an old style state. Unwrap to a simple state object + // Remove after 1.37 + if ('state' in (state as any) && typeof (state as any).state === 'string') { + return (state as any).state; + } + return undefined; +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts index ab03a02e70..6d3731fb80 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts @@ -7,13 +7,14 @@ import { equals } from 'vs/base/common/arrays'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; -import { IWebviewOptions, IWebviewPanelOptions } from 'vs/editor/common/modes'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { GroupIdentifier } from 'vs/workbench/common/editor'; +import { IWebviewService, WebviewOptions, WebviewContentOptions } from 'vs/workbench/contrib/webview/common/webview'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; import { RevivedWebviewEditorInput, WebviewEditorInput } from './webviewEditorInput'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export const IWebviewEditorService = createDecorator('webviewEditorService'); @@ -35,7 +36,6 @@ export interface IWebviewEditorService { location: URI, id: ExtensionIdentifier }, - events: WebviewEvents ): WebviewEditorInput; reviveWebview( @@ -77,25 +77,20 @@ export interface WebviewReviver { ): Promise; } -export interface WebviewEvents { - onMessage?(message: any): void; - onDispose?(): void; - onDidClickLink?(link: URI, options: IWebviewOptions): void; - onDidUpdateWebviewState?(newState: any): void; -} - -export interface WebviewInputOptions extends IWebviewOptions, IWebviewPanelOptions { - tryRestoreScrollPosition?: boolean; +export interface WebviewInputOptions extends WebviewOptions, WebviewContentOptions { + readonly tryRestoreScrollPosition?: boolean; + readonly retainContextWhenHidden?: boolean; + readonly enableCommandUris?: boolean; } export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewInputOptions): boolean { return a.enableCommandUris === b.enableCommandUris && a.enableFindWidget === b.enableFindWidget - && a.enableScripts === b.enableScripts + && a.allowScripts === b.allowScripts && a.retainContextWhenHidden === b.retainContextWhenHidden && a.tryRestoreScrollPosition === b.tryRestoreScrollPosition && (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString()))) - && (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); + && (a.portMappings === b.portMappings || (Array.isArray(a.portMappings) && Array.isArray(b.portMappings) && equals(a.portMappings, b.portMappings, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); } function canRevive(reviver: WebviewReviver, webview: WebviewEditorInput): boolean { @@ -132,6 +127,8 @@ export class WebviewEditorService implements IWebviewEditorService { @IEditorService private readonly _editorService: IEditorService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, + @IWebviewService private readonly _webviewService: IWebviewService, + @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, ) { } public createWebview( @@ -139,14 +136,15 @@ export class WebviewEditorService implements IWebviewEditorService { viewType: string, title: string, showOptions: ICreateWebViewShowOptions, - options: IWebviewOptions, + options: WebviewInputOptions, extension: undefined | { location: URI, id: ExtensionIdentifier }, - events: WebviewEvents ): WebviewEditorInput { - const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, options, {}, events, extension); + const webview = this.createWebiew(id, extension, options); + + const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, webview); this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group); return webviewInput; } @@ -175,11 +173,14 @@ export class WebviewEditorService implements IWebviewEditorService { options: WebviewInputOptions, extension: undefined | { readonly location: URI, - readonly id?: ExtensionIdentifier + readonly id: ExtensionIdentifier }, group: number | undefined, ): WebviewEditorInput { - const webviewInput = this._instantiationService.createInstance(RevivedWebviewEditorInput, id, viewType, title, options, state, {}, extension, async (webview: WebviewEditorInput): Promise => { + const webview = this.createWebiew(id, extension, options); + webview.state = state; + + const webviewInput = new RevivedWebviewEditorInput(id, viewType, title, extension, async (webview: WebviewEditorInput): Promise => { const didRevive = await this.tryRevive(webview); if (didRevive) { return Promise.resolve(undefined); @@ -190,8 +191,10 @@ export class WebviewEditorService implements IWebviewEditorService { const promise = new Promise(r => { resolve = r; }); this._revivalPool.add(webview, resolve!); return promise; - }); + }, webview); + webviewInput.iconPath = iconPath; + if (typeof group === 'number') { webviewInput.updateGroup(group); } @@ -213,7 +216,7 @@ export class WebviewEditorService implements IWebviewEditorService { webview: WebviewEditorInput ): boolean { // Has no state, don't persist - if (!webview.state) { + if (!webview.webview.state) { return false; } @@ -237,4 +240,27 @@ export class WebviewEditorService implements IWebviewEditorService { } return false; } + + private createWebiew(id: string, extension: { location: URI; id: ExtensionIdentifier; } | undefined, options: WebviewInputOptions) { + return this._webviewService.createWebviewEditorOverlay(id, { + allowSvgs: true, + extension: extension, + enableFindWidget: options.enableFindWidget, + retainContextWhenHidden: options.retainContextWhenHidden + }, { + ...options, + localResourceRoots: options.localResourceRoots || this.getDefaultLocalResourceRoots(extension), + }); + } + + private getDefaultLocalResourceRoots(extension: undefined | { + location: URI, + id: ExtensionIdentifier + }): URI[] { + const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri); + if (extension) { + rootPaths.push(extension.location); + } + return rootPaths; + } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 53a926d48c..f8ee04030a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -155,7 +155,7 @@ export class IFrameWebview extends Disposable implements Webview { } } - public set options(options: WebviewContentOptions) { + public set contentOptions(options: WebviewContentOptions) { if (areWebviewInputOptionsEqual(options, this.content.options)) { return; } diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index 5b01459905..3ccda53900 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -3,9 +3,14 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IFrameWebview as WebviewElement } from 'vs/workbench/contrib/webview/browser/webviewElement'; -import { IWebviewService, WebviewOptions, WebviewContentOptions, Webview } from 'vs/workbench/contrib/webview/common/webview'; +import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; +import { memoize } from 'vs/base/common/decorators'; export class WebviewService implements IWebviewService { _serviceBrand: any; @@ -18,10 +23,178 @@ export class WebviewService implements IWebviewService { id: string, options: WebviewOptions, contentOptions: WebviewContentOptions - ): Webview { - return this._instantiationService.createInstance(WebviewElement, - id, - options, - contentOptions); + ): WebviewElement { + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); + } + + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay { + return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions); + } +} + +/** + * Webview editor overlay that creates and destroys the underlying webview as needed. + */ +class DynamicWebviewEditorOverlay extends Disposable implements WebviewEditorOverlay { + + private readonly _pendingMessages = new Set(); + private readonly _webview = this._register(new MutableDisposable()); + private readonly _webviewEvents = this._register(new DisposableStore()); + + private _html: string = ''; + private _initialScrollProgress: number = 0; + private _state: string | undefined = undefined; + private _owner: any = undefined; + + public constructor( + private readonly id: string, + public readonly options: WebviewOptions, + private _contentOptions: WebviewContentOptions, + @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, + @IWebviewService private readonly _webviewService: IWebviewService, + ) { + super(); + + this._register(toDisposable(() => this.container.remove())); + } + + @memoize + public get container() { + const container = document.createElement('div'); + container.id = `webview-${this.id}`; + this._layoutService.getContainer(Parts.EDITOR_PART).appendChild(container); + return container; + } + + public claim(owner: any) { + this._owner = owner; + this.show(); + } + + public release(owner: any) { + if (this._owner !== owner) { + return; + } + + this._owner = undefined; + this.container.style.visibility = 'hidden'; + if (!this.options.retainContextWhenHidden) { + this._webview.clear(); + this._webviewEvents.clear(); + } + } + + private show() { + if (!this._webview.value) { + const webview = this._webviewService.createWebview(this.id, this.options, this._contentOptions); + this._webview.value = webview; + webview.state = this._state; + webview.html = this._html; + + if (this.options.tryRestoreScrollPosition) { + webview.initialScrollProgress = this._initialScrollProgress; + } + + this._webview.value.mountTo(this.container); + + this._webviewEvents.clear(); + + webview.onDidFocus(() => { + this._onDidFocus.fire(); + }, undefined, this._webviewEvents); + + webview.onDidClickLink(x => { + this._onDidClickLink.fire(x); + }, undefined, this._webviewEvents); + + webview.onDidScroll(x => { + this._initialScrollProgress = x.scrollYPercentage; + this._onDidScroll.fire(x); + }, undefined, this._webviewEvents); + + webview.onDidUpdateState(state => { + this._state = state; + this._onDidUpdateState.fire(state); + }, undefined, this._webviewEvents); + + webview.onMessage(x => { + this._onMessage.fire(x); + }, undefined, this._webviewEvents); + + this._pendingMessages.forEach(msg => webview.sendMessage(msg)); + this._pendingMessages.clear(); + } + this.container.style.visibility = 'visible'; + } + + public get html(): string { return this._html; } + public set html(value: string) { + this._html = value; + this.withWebview(webview => webview.html = value); + } + + public get initialScrollProgress(): number { return this._initialScrollProgress; } + public set initialScrollProgress(value: number) { + this._initialScrollProgress = value; + this.withWebview(webview => webview.initialScrollProgress = value); + } + + public get state(): string | undefined { return this._state; } + public set state(value: string | undefined) { + this._state = value; + this.withWebview(webview => webview.state = value); + } + + public get contentOptions(): WebviewContentOptions { return this._contentOptions; } + public set contentOptions(value: WebviewContentOptions) { + this._contentOptions = value; + this.withWebview(webview => webview.contentOptions = value); + } + + private readonly _onDidFocus = this._register(new Emitter()); + public readonly onDidFocus: Event = this._onDidFocus.event; + + private readonly _onDidClickLink = this._register(new Emitter()); + public readonly onDidClickLink: Event = this._onDidClickLink.event; + + private readonly _onDidScroll = this._register(new Emitter<{ scrollYPercentage: number; }>()); + public readonly onDidScroll: Event<{ scrollYPercentage: number; }> = this._onDidScroll.event; + + private readonly _onDidUpdateState = this._register(new Emitter()); + public readonly onDidUpdateState: Event = this._onDidUpdateState.event; + + private readonly _onMessage = this._register(new Emitter()); + public readonly onMessage: Event = this._onMessage.event; + + sendMessage(data: any): void { + if (this._webview.value) { + this._webview.value.sendMessage(data); + } else { + this._pendingMessages.add(data); + } + } + + update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean): void { + this._contentOptions = options; + this._html = html; + this.withWebview(webview => { + webview.update(html, options, retainContextWhenHidden); + }); + } + + layout(): void { this.withWebview(webview => webview.layout()); } + focus(): void { this.withWebview(webview => webview.focus()); } + reload(): void { this.withWebview(webview => webview.reload()); } + showFind(): void { this.withWebview(webview => webview.showFind()); } + hideFind(): void { this.withWebview(webview => webview.hideFind()); } + + private withWebview(f: (webview: Webview) => void): void { + if (this._webview.value) { + f(this._webview.value); + } } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index 40db7d7fed..7616ceab2a 100644 --- a/src/vs/workbench/contrib/webview/common/webview.ts +++ b/src/vs/workbench/contrib/webview/common/webview.ts @@ -7,10 +7,10 @@ import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import * as modes from 'vs/editor/common/modes'; +import * as nls from 'vs/nls'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import * as nls from 'vs/nls'; /** * Set when the find widget in a webview is visible. @@ -29,7 +29,13 @@ export interface IWebviewService { id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, - ): Webview; + ): WebviewElement; + + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay; } export const WebviewResourceScheme = 'vscode-resource'; @@ -41,6 +47,8 @@ export interface WebviewOptions { readonly id?: ExtensionIdentifier; }; readonly enableFindWidget?: boolean; + readonly tryRestoreScrollPosition?: boolean; + readonly retainContextWhenHidden?: boolean; } export interface WebviewContentOptions { @@ -48,12 +56,13 @@ export interface WebviewContentOptions { readonly svgWhiteList?: string[]; readonly localResourceRoots?: ReadonlyArray; readonly portMappings?: ReadonlyArray; + readonly enableCommandUris?: boolean; } export interface Webview extends IDisposable { html: string; - options: WebviewContentOptions; + contentOptions: WebviewContentOptions; initialScrollProgress: number; state: string | undefined; @@ -65,13 +74,12 @@ export interface Webview extends IDisposable { sendMessage(data: any): void; update( - value: string, + html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean ): void; layout(): void; - mountTo(parent: HTMLElement): void; focus(): void; reload(): void; @@ -79,4 +87,16 @@ export interface Webview extends IDisposable { hideFind(): void; } +export interface WebviewElement extends Webview { + mountTo(parent: HTMLElement): void; +} + +export interface WebviewEditorOverlay extends Webview { + readonly container: HTMLElement; + readonly options: WebviewOptions; + + claim(owner: any): void; + release(owner: any): void; +} + export const webviewDeveloperCategory = nls.localize('developer', "Developer"); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts index f3390ed47d..3456f99e02 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import { Command, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; export class OpenWebviewDeveloperToolsAction extends Action { static readonly ID = 'workbench.action.webview.openDeveloperTools'; @@ -86,11 +86,11 @@ function getActiveWebviewEditor(accessor: ServicesAccessor): WebviewEditor | und return activeControl.isWebviewEditor ? activeControl : undefined; } -function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: WebviewElement) => void): void { +function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: ElectronWebviewBasedWebview) => void): void { const webViewEditor = getActiveWebviewEditor(accessor); if (webViewEditor) { webViewEditor.withWebview(webview => { - if (webview instanceof WebviewElement) { + if (webview instanceof ElectronWebviewBasedWebview) { f(webview); } }); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 5c58b20395..4a2d2bb9ec 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -13,7 +13,6 @@ import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import * as modes from 'vs/editor/common/modes'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; @@ -25,27 +24,6 @@ import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-brow import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService'; import { WebviewFindWidget } from '../browser/webviewFindWidget'; -export interface WebviewPortMapping { - readonly port: number; - readonly resolvedPort: number; -} - -export interface WebviewOptions { - readonly allowSvgs?: boolean; - readonly extension?: { - readonly location: URI; - readonly id?: ExtensionIdentifier; - }; - readonly enableFindWidget?: boolean; -} - -export interface WebviewContentOptions { - readonly allowScripts?: boolean; - readonly svgWhiteList?: string[]; - readonly localResourceRoots?: ReadonlyArray; - readonly portMappings?: ReadonlyArray; -} - interface IKeydownEvent { key: string; keyCode: number; @@ -285,7 +263,7 @@ interface WebviewContent { readonly state: string | undefined; } -export class WebviewElement extends Disposable implements Webview { +export class ElectronWebviewBasedWebview extends Disposable implements Webview { private _webview: Electron.WebviewTag | undefined; private _ready: Promise; @@ -508,7 +486,7 @@ export class WebviewElement extends Disposable implements Webview { }; } - public set options(options: WebviewContentOptions) { + public set contentOptions(options: WebviewContentOptions) { if (areWebviewInputOptionsEqual(options, this.content.options)) { return; } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts index af3447e078..53a7098aff 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts @@ -4,23 +4,24 @@ *--------------------------------------------------------------------------------------------*/ import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWebviewService, Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { WebviewService as BrowserWebviewService } from 'vs/workbench/contrib/webview/browser/webviewService'; +import { IWebviewService, WebviewContentOptions, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; -export class WebviewService implements IWebviewService { +export class WebviewService extends BrowserWebviewService implements IWebviewService { _serviceBrand: any; constructor( - @IInstantiationService private readonly _instantiationService: IInstantiationService, - ) { } + @IInstantiationService private readonly instantiationService: IInstantiationService, + ) { + super(instantiationService); + } createWebview( _id: string, options: WebviewOptions, contentOptions: WebviewContentOptions - ): Webview { - return this._instantiationService.createInstance(WebviewElement, - options, - contentOptions); + ): WebviewElement { + return this.instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions); } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts index 525b019d8a..f8c00b6abf 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts @@ -110,12 +110,14 @@ export class TelemetryOptOut implements IWorkbenchContribution { } const logTelemetry = (optout?: boolean) => { - /* __GDPR__ - "experiments:optout" : { - "optOut": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('experiments:optout', typeof optout === 'boolean' ? { optout } : {}); + type ExperimentsOptOutClassification = { + optout?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + + type ExperimentsOptOutEvent = { + optout?: boolean; + }; + this.telemetryService.publicLog2('experiments:optout', typeof optout === 'boolean' ? { optout } : {}); }; queryPromise.then(() => { diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 6d46fee585..508cd78a17 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -22,9 +22,9 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Schemas } from 'vs/base/common/network'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { getInstalledExtensions, IExtensionStatus, onExtensionChanged, isKeymapExtension } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; -import { IExtensionEnablementService, IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, EnablementState, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; -// {{SQL CARBON EDIT}} - Redirect to ADS welcome page -import { used } from 'sql/workbench/contrib/welcome/page/browser/az_data_welcome_page'; +import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { used } from 'sql/workbench/contrib/welcome/page/browser/az_data_welcome_page'; // {{SQL CARBON EDIT}} - Redirect to ADS welcome page import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle'; import { splitName } from 'vs/base/common/labels'; @@ -459,7 +459,7 @@ class WelcomePage extends Disposable { .then(installed => { const local = installed.filter(i => areSameExtensions(extension.identifier, i.identifier))[0]; // TODO: Do this as part of the install to avoid multiple events. - return this.extensionEnablementService.setEnablement([local], EnablementState.Disabled).then(() => local); + return this.extensionEnablementService.setEnablement([local], EnablementState.DisabledGlobally).then(() => local); }); }); @@ -474,12 +474,12 @@ class WelcomePage extends Disposable { this.notificationService.info(strings.installing.replace('{0}', extensionSuggestion.name)); }, 300); const extensionsToDisable = extensions.filter(extension => isKeymapExtension(this.tipsService, extension) && extension.globallyEnabled).map(extension => extension.local); - extensionsToDisable.length ? this.extensionEnablementService.setEnablement(extensionsToDisable, EnablementState.Disabled) : Promise.resolve() + extensionsToDisable.length ? this.extensionEnablementService.setEnablement(extensionsToDisable, EnablementState.DisabledGlobally) : Promise.resolve() .then(() => { return foundAndInstalled.then(foundExtension => { messageDelay.cancel(); if (foundExtension) { - return this.extensionEnablementService.setEnablement([foundExtension], EnablementState.Enabled) + return this.extensionEnablementService.setEnablement([foundExtension], EnablementState.EnabledGlobally) .then(() => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-2" : { diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index 4180e3ea56..c794c3c8c8 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -356,43 +356,33 @@ export class WalkThroughPart extends BaseEditor { } })); + type WalkThroughSnippetInteractionClassification = { + from?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + snippet: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WalkThroughSnippetInteractionEvent = { + from?: string, + type: string, + snippet: number + }; + this.contentDisposables.push(Event.once(editor.onMouseDown)(() => { - /* __GDPR__ - "walkThroughSnippetInteraction" : { - "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('walkThroughSnippetInteraction', { + this.telemetryService.publicLog2('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'mouseDown', snippet: i }); })); this.contentDisposables.push(Event.once(editor.onKeyDown)(() => { - /* __GDPR__ - "walkThroughSnippetInteraction" : { - "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('walkThroughSnippetInteraction', { + this.telemetryService.publicLog2('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'keyDown', snippet: i }); })); this.contentDisposables.push(Event.once(editor.onDidChangeModelContent)(() => { - /* __GDPR__ - "walkThroughSnippetInteraction" : { - "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('walkThroughSnippetInteraction', { + this.telemetryService.publicLog2('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'changeModelContent', snippet: i diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 0ad99b32ba..3c4fabcdf8 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -135,13 +135,11 @@ export class ElectronWindow extends Disposable { try { await this.commandService.executeCommand(request.id, ...args); - /* __GDPR__ - "commandExecuted" : { - "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('commandExecuted', { id: request.id, from: request.from }); + type CommandExecutedClassifcation = { + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + from: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ id: String, from: String }, CommandExecutedClassifcation>('commandExecuted', { id: request.id, from: request.from }); } catch (error) { this.notificationService.error(error); } diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 81b9f0a070..2ba5f192a8 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -91,6 +91,36 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService { this.webviewEndpoint = configuration.webviewEndpoint; this.untitledWorkspacesHome = URI.from({ scheme: Schemas.untitled, path: 'Workspaces' }); + + if (document && document.location && document.location.search) { + + const map = new Map(); + const query = document.location.search.substring(1); + const vars = query.split('&'); + for (let p of vars) { + const pair = p.split('='); + if (pair.length >= 2) { + map.set(decodeURIComponent(pair[0]), decodeURIComponent(pair[1])); + } + } + + const edp = map.get('edp'); + if (edp) { + this.extensionDevelopmentLocationURI = [URI.parse(edp)]; + this.isExtensionDevelopment = true; + } + + const di = map.get('di'); + if (di) { + this.debugExtensionHost.debugId = di; + } + + const ibe = map.get('ibe'); + if (ibe) { + this.debugExtensionHost.port = parseInt(ibe); + this.debugExtensionHost.break = false; + } + } } untitledWorkspacesHome: URI; @@ -119,7 +149,7 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService { isExtensionDevelopment: boolean; disableExtensions: boolean | string[]; builtinExtensionsPath: string; - extensionsPath: string; + extensionsPath?: string; extensionDevelopmentLocationURI?: URI[]; extensionTestsPath?: string; debugExtensionHost: IExtensionHostDebugParams; @@ -143,6 +173,7 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService { driverHandle?: string; driverVerbose: boolean; webviewEndpoint?: string; + galleryMachineIdResource?: URI; get webviewResourceRoot(): string { return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource{{resource}}' : 'vscode-resource:{{resource}}'; diff --git a/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts similarity index 89% rename from src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts rename to src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts index 4755baa5ee..b6e33975db 100644 --- a/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts @@ -6,7 +6,8 @@ import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, DidInstallExtensionEvent, InstallOperation, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionIdentifier, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; @@ -55,30 +56,34 @@ export class ExtensionEnablementService extends Disposable implements IExtension } getEnablementState(extension: IExtension): EnablementState { - if (this._isSystemDisabled(extension)) { - return EnablementState.Disabled; + if (this._isDisabledInEnv(extension)) { + return EnablementState.DisabledByEnvironemt; + } + if (this._isDisabledByExtensionKind(extension)) { + return EnablementState.DisabledByExtensionKind; } const identifier = extension.identifier; if (this.hasWorkspace) { if (this._getEnabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceEnabled; + return EnablementState.EnabledWorkspace; } if (this._getDisabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceDisabled; + return EnablementState.DisabledWorkspace; } } if (this._getDisabledExtensions(StorageScope.GLOBAL).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.Disabled; + return EnablementState.DisabledGlobally; } - return EnablementState.Enabled; + return EnablementState.EnabledGlobally; } canChangeEnablement(extension: IExtension): boolean { if (extension.manifest && extension.manifest.contributes && extension.manifest.contributes.localizations && extension.manifest.contributes.localizations.length) { return false; } - if (this._isSystemDisabled(extension)) { + const enablementState = this.getEnablementState(extension); + if (enablementState === EnablementState.DisabledByEnvironemt || enablementState === EnablementState.DisabledByExtensionKind) { return false; } return true; @@ -86,7 +91,7 @@ export class ExtensionEnablementService extends Disposable implements IExtension async setEnablement(extensions: IExtension[], newState: EnablementState): Promise { - const workspace = newState === EnablementState.WorkspaceDisabled || newState === EnablementState.WorkspaceEnabled; + const workspace = newState === EnablementState.DisabledWorkspace || newState === EnablementState.EnabledWorkspace; if (workspace && !this.hasWorkspace) { return Promise.reject(new Error(localize('noWorkspace', "No workspace."))); } @@ -108,16 +113,16 @@ export class ExtensionEnablementService extends Disposable implements IExtension } switch (newState) { - case EnablementState.Enabled: + case EnablementState.EnabledGlobally: this._enableExtension(extension.identifier); break; - case EnablementState.Disabled: + case EnablementState.DisabledGlobally: this._disableExtension(extension.identifier); break; - case EnablementState.WorkspaceEnabled: + case EnablementState.EnabledWorkspace: this._enableExtensionInWorkspace(extension.identifier); break; - case EnablementState.WorkspaceDisabled: + case EnablementState.DisabledWorkspace: this._disableExtensionInWorkspace(extension.identifier); break; } @@ -127,10 +132,10 @@ export class ExtensionEnablementService extends Disposable implements IExtension isEnabled(extension: IExtension): boolean { const enablementState = this.getEnablementState(extension); - return enablementState === EnablementState.WorkspaceEnabled || enablementState === EnablementState.Enabled; + return enablementState === EnablementState.EnabledWorkspace || enablementState === EnablementState.EnabledGlobally; } - private _isSystemDisabled(extension: IExtension): boolean { + private _isDisabledInEnv(extension: IExtension): boolean { if (this.allUserExtensionsDisabled) { return extension.type === ExtensionType.User; } @@ -138,7 +143,11 @@ export class ExtensionEnablementService extends Disposable implements IExtension if (Array.isArray(disabledExtensions)) { return disabledExtensions.some(id => areSameExtensions({ id }, extension.identifier)); } - if (this.environmentService.configuration.remoteAuthority) { + return false; + } + + private _isDisabledByExtensionKind(extension: IExtension): boolean { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { const server = isUIExtension(extension.manifest, this.productService, this.configurationService) ? this.extensionManagementServerService.localExtensionManagementServer : this.extensionManagementServerService.remoteExtensionManagementServer; return this.extensionManagementServerService.getExtensionManagementServer(extension.location) !== server; } @@ -148,17 +157,17 @@ export class ExtensionEnablementService extends Disposable implements IExtension private _getEnablementState(identifier: IExtensionIdentifier): EnablementState { if (this.hasWorkspace) { if (this._getEnabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceEnabled; + return EnablementState.EnabledWorkspace; } if (this._getDisabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceDisabled; + return EnablementState.DisabledWorkspace; } } if (this._getDisabledExtensions(StorageScope.GLOBAL).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.Disabled; + return EnablementState.DisabledGlobally; } - return EnablementState.Enabled; + return EnablementState.EnabledGlobally; } private _enableExtension(identifier: IExtensionIdentifier): void { diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts new file mode 100644 index 0000000000..2383d94fcb --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -0,0 +1,117 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event } from 'vs/base/common/event'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { URI } from 'vs/base/common/uri'; +import { IExtension } from 'vs/platform/extensions/common/extensions'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IWorkspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; + +export const IExtensionManagementServerService = createDecorator('extensionManagementServerService'); + +export interface IExtensionManagementServer { + extensionManagementService: IExtensionManagementService; + authority: string; + label: string; +} + +export interface IExtensionManagementServerService { + _serviceBrand: any; + readonly localExtensionManagementServer: IExtensionManagementServer | null; + readonly remoteExtensionManagementServer: IExtensionManagementServer | null; + getExtensionManagementServer(location: URI): IExtensionManagementServer | null; +} + +export const enum EnablementState { + DisabledByExtensionKind, + DisabledByEnvironemt, + DisabledGlobally, + DisabledWorkspace, + EnabledGlobally, + EnabledWorkspace +} + +export const IExtensionEnablementService = createDecorator('extensionEnablementService'); + +export interface IExtensionEnablementService { + _serviceBrand: any; + + readonly allUserExtensionsDisabled: boolean; + + /** + * Event to listen on for extension enablement changes + */ + onEnablementChanged: Event; + + /** + * Returns the enablement state for the given extension + */ + getEnablementState(extension: IExtension): EnablementState; + + /** + * Returns `true` if the enablement can be changed. + */ + canChangeEnablement(extension: IExtension): boolean; + + /** + * Returns `true` if the given extension identifier is enabled. + */ + isEnabled(extension: IExtension): boolean; + + /** + * Enable or disable the given extension. + * if `workspace` is `true` then enablement is done for workspace, otherwise globally. + * + * Returns a promise that resolves to boolean value. + * if resolves to `true` then requires restart for the change to take effect. + * + * Throws error if enablement is requested for workspace and there is no workspace + */ + setEnablement(extensions: IExtension[], state: EnablementState): Promise; +} + +export interface IExtensionsConfigContent { + recommendations: string[]; + unwantedRecommendations: string[]; +} + +export type RecommendationChangeNotification = { + extensionId: string, + isRecommended: boolean +}; + +export type DynamicRecommendation = 'dynamic'; +export type ExecutableRecommendation = 'executable'; +export type CachedRecommendation = 'cached'; +export type ApplicationRecommendation = 'application'; +export type ExtensionRecommendationSource = IWorkspace | IWorkspaceFolder | URI | DynamicRecommendation | ExecutableRecommendation | CachedRecommendation | ApplicationRecommendation; + +export interface IExtensionRecommendation { + extensionId: string; + sources: ExtensionRecommendationSource[]; +} + +export const IExtensionTipsService = createDecorator('extensionTipsService'); + +export interface IExtensionTipsService { + _serviceBrand: any; + getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; }; + getFileBasedRecommendations(): IExtensionRecommendation[]; + getOtherRecommendations(): Promise; + getWorkspaceRecommendations(): Promise; + getKeymapRecommendations(): IExtensionRecommendation[]; + toggleIgnoredRecommendation(extensionId: string, shouldIgnore: boolean): void; + getAllIgnoredRecommendations(): { global: string[], workspace: string[] }; + onRecommendationChange: Event; +} + +export const enum ExtensionRecommendationReason { + Workspace, + File, + Executable, + DynamicWorkspace, + Experimental +} diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts new file mode 100644 index 0000000000..019d4f7b39 --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { URI } from 'vs/base/common/uri'; +import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILabelService } from 'vs/platform/label/common/label'; + +export class ExtensionManagementServerService implements IExtensionManagementServerService { + + _serviceBrand: any; + + readonly localExtensionManagementServer: IExtensionManagementServer | null = null; + readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; + + constructor( + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + @ILabelService labelService: ILabelService, + ) { + const remoteAgentConnection = remoteAgentService.getConnection(); + if (remoteAgentConnection) { + const extensionManagementService = new ExtensionManagementChannelClient(remoteAgentConnection!.getChannel('extensions')); + this.remoteExtensionManagementServer = { + authority: remoteAgentConnection.remoteAuthority, extensionManagementService, + get label() { return labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAgentConnection!.remoteAuthority) || localize('remote', "Remote"); } + }; + } + } + + getExtensionManagementServer(location: URI): IExtensionManagementServer | null { + if (location.scheme === REMOTE_HOST_SCHEME) { + return this.remoteExtensionManagementServer; + } + return null; + } +} + +registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService); \ No newline at end of file diff --git a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts similarity index 70% rename from src/vs/workbench/services/extensions/node/multiExtensionManagement.ts rename to src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index af62e0bdfc..1472122f4d 100644 --- a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -5,22 +5,20 @@ import { Event, EventMultiplexer } from 'vs/base/common/event'; import { - IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, - IExtensionManagementServerService, IExtensionManagementServer, IExtensionGalleryService + IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionType, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localize } from 'vs/nls'; import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IProductService } from 'vs/platform/product/common/product'; -export class MultiExtensionManagementService extends Disposable implements IExtensionManagementService { +export class ExtensionManagementService extends Disposable implements IExtensionManagementService { _serviceBrand: any; @@ -29,16 +27,21 @@ export class MultiExtensionManagementService extends Disposable implements IExte readonly onUninstallExtension: Event; readonly onDidUninstallExtension: Event; - private readonly servers: IExtensionManagementServer[]; + protected readonly servers: IExtensionManagementServer[] = []; constructor( - @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, + @IConfigurationService protected readonly configurationService: IConfigurationService, + @IProductService protected readonly productService: IProductService, ) { super(); - this.servers = this.extensionManagementServerService.remoteExtensionManagementServer ? [this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer] : [this.extensionManagementServerService.localExtensionManagementServer]; + if (this.extensionManagementServerService.localExtensionManagementServer) { + this.servers.push(this.extensionManagementServerService.localExtensionManagementServer); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + this.servers.push(this.extensionManagementServerService.remoteExtensionManagementServer); + } this.onInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onInstallExtension); return emitter; }, new EventMultiplexer())).event; this.onDidInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidInstallExtension); return emitter; }, new EventMultiplexer())).event; @@ -53,31 +56,33 @@ export class MultiExtensionManagementService extends Disposable implements IExte .catch(e => installedExtensions); } - async uninstall(extension: ILocalExtension, force?: boolean): Promise { - if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const server = this.getServer(extension); - if (!server) { - return Promise.reject(`Invalid location ${extension.location.toString()}`); - } - if (isLanguagePackExtension(extension.manifest)) { - return this.uninstallEverywhere(extension, force); - } - return this.uninstallInServer(extension, server, force); + async uninstall(extension: ILocalExtension): Promise { + const server = this.getServer(extension); + if (!server) { + return Promise.reject(`Invalid location ${extension.location.toString()}`); } - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.uninstall(extension, force); + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + if (isLanguagePackExtension(extension.manifest)) { + return this.uninstallEverywhere(extension); + } + return this.uninstallInServer(extension, server); + } + return server.extensionManagementService.uninstall(extension); } - private async uninstallEverywhere(extension: ILocalExtension, force?: boolean): Promise { + private async uninstallEverywhere(extension: ILocalExtension): Promise { const server = this.getServer(extension); if (!server) { return Promise.reject(`Invalid location ${extension.location.toString()}`); } const promise = server.extensionManagementService.uninstall(extension); - const anotherServer: IExtensionManagementServer = server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer! : this.extensionManagementServerService.localExtensionManagementServer; - const installed = await anotherServer.extensionManagementService.getInstalled(ExtensionType.User); - extension = installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0]; - if (extension) { - await anotherServer.extensionManagementService.uninstall(extension); + const anotherServer: IExtensionManagementServer | null = server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer! : this.extensionManagementServerService.localExtensionManagementServer; + if (anotherServer) { + const installed = await anotherServer.extensionManagementService.getInstalled(ExtensionType.User); + extension = installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0]; + if (extension) { + await anotherServer.extensionManagementService.uninstall(extension); + } } return promise; } @@ -133,25 +138,17 @@ export class MultiExtensionManagementService extends Disposable implements IExte } async install(vsix: URI): Promise { + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + } if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const manifest = await getManifest(vsix.fsPath); - if (isLanguagePackExtension(manifest)) { - // Install on both servers - const [local] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix))); - return local; - } - if (isUIExtension(manifest, this.productService, this.configurationService)) { - // Install only on local server - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); - } - // Install only on remote server return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.install(vsix); } - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + return Promise.reject('No Servers to Install'); } async installFromGallery(gallery: IGalleryExtension): Promise { - if (this.extensionManagementServerService.remoteExtensionManagementServer) { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { const manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None); if (manifest) { if (isLanguagePackExtension(manifest)) { @@ -168,16 +165,26 @@ export class MultiExtensionManagementService extends Disposable implements IExte return Promise.reject(localize('Manifest is not found', "Installing Extension {0} failed: Manifest is not found.", gallery.displayName || gallery.name)); } } - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + } + return Promise.reject('No Servers to Install'); } getExtensionsReport(): Promise { - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.getExtensionsReport(); + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.getExtensionsReport(); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.getExtensionsReport(); + } + return Promise.resolve([]); } private getServer(extension: ILocalExtension): IExtensionManagementServer | null { return this.extensionManagementServerService.getExtensionManagementServer(extension.location); } } - -registerSingleton(IExtensionManagementService, MultiExtensionManagementService); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts similarity index 80% rename from src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts index 551043ae78..143de0d0b9 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts @@ -6,8 +6,9 @@ import { localize } from 'vs/nls'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; -import { IExtensionManagementServer, IExtensionManagementServerService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; +import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; @@ -17,6 +18,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { RemoteExtensionManagementChannelClient } from 'vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProductService } from 'vs/platform/product/common/product'; +import { ILabelService } from 'vs/platform/label/common/label'; const localExtensionManagementServerAuthority: string = 'vscode-local'; @@ -26,6 +28,7 @@ export class ExtensionManagementServerService implements IExtensionManagementSer readonly localExtensionManagementServer: IExtensionManagementServer; readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; + readonly isSingleServer: boolean = false; constructor( @ISharedProcessService sharedProcessService: ISharedProcessService, @@ -33,7 +36,8 @@ export class ExtensionManagementServerService implements IExtensionManagementSer @IExtensionGalleryService galleryService: IExtensionGalleryService, @IConfigurationService configurationService: IConfigurationService, @IProductService productService: IProductService, - @ILogService logService: ILogService + @ILogService logService: ILogService, + @ILabelService labelService: ILabelService, ) { const localExtensionManagementService = new ExtensionManagementChannelClient(sharedProcessService.getChannel('extensions')); @@ -41,7 +45,10 @@ export class ExtensionManagementServerService implements IExtensionManagementSer const remoteAgentConnection = remoteAgentService.getConnection(); if (remoteAgentConnection) { const extensionManagementService = new RemoteExtensionManagementChannelClient(remoteAgentConnection.getChannel('extensions'), this.localExtensionManagementServer.extensionManagementService, galleryService, logService, configurationService, productService); - this.remoteExtensionManagementServer = { authority: remoteAgentConnection.remoteAuthority, extensionManagementService, label: localize('remote', "Remote") }; + this.remoteExtensionManagementServer = { + authority: remoteAgentConnection.remoteAuthority, extensionManagementService, + get label() { return labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAgentConnection!.remoteAuthority) || localize('remote', "Remote"); } + }; } } diff --git a/src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts new file mode 100644 index 0000000000..44eee62a69 --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; +import { URI } from 'vs/base/common/uri'; +import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { ExtensionManagementService as BaseExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; + +export class ExtensionManagementService extends BaseExtensionManagementService { + + async install(vsix: URI): Promise { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + const manifest = await getManifest(vsix.fsPath); + if (isLanguagePackExtension(manifest)) { + // Install on both servers + const [local] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix))); + return local; + } + if (isUIExtension(manifest, this.productService, this.configurationService)) { + // Install only on local server + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + } + // Install only on remote server + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.install(vsix); + } + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + } + return Promise.reject('No Servers to Install'); + } + +} diff --git a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index a35380c732..baa4f189d8 100644 --- a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -4,8 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as sinon from 'sinon'; -import { IExtensionManagementService, IExtensionEnablementService, DidUninstallExtensionEvent, EnablementState, ILocalExtension, DidInstallExtensionEvent, InstallOperation, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionEnablementService } from 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; +import { IExtensionManagementService, DidUninstallExtensionEvent, ILocalExtension, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { Emitter } from 'vs/base/common/event'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -16,6 +17,11 @@ import { isUndefinedOrNull } from 'vs/base/common/types'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ProductService } from 'vs/platform/product/node/productService'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { assign } from 'vs/base/common/objects'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; function storageService(instantiationService: TestInstantiationService): IStorageService { let service = instantiationService.get(IStorageService); @@ -55,7 +61,7 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { if (workspaceEnabledExtensions.length) { extensions = extensions.filter(r => !workspaceEnabledExtensions.some(e => areSameExtensions(e, r))); } - extensions.forEach(d => this.setEnablement([aLocalExtension(d.id)], EnablementState.Enabled)); + extensions.forEach(d => this.setEnablement([aLocalExtension(d.id)], EnablementState.EnabledGlobally)); } } @@ -69,7 +75,13 @@ suite('ExtensionEnablementService Test', () => { setup(() => { instantiationService = new TestInstantiationService(); + instantiationService.stub(IConfigurationService, new TestConfigurationService()); instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([] as ILocalExtension[]) } as IExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, { + localExtensionManagementServer: { + extensionManagementService: instantiationService.get(IExtensionManagementService) + } + }); testObject = new TestExtensionEnablementService(instantiationService); }); @@ -79,20 +91,20 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.Disabled); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Disabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledGlobally); }); test('test disable an extension globally should return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(value => assert.ok(value)); }); test('test disable an extension globally triggers the change event', () => { const target = sinon.spy(); testObject.onEnablementChanged(target); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -100,116 +112,116 @@ suite('ExtensionEnablementService Test', () => { }); test('test disable an extension globally again should return a falsy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) .then(value => assert.ok(!value[0])); }); test('test state of globally disabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledGlobally)); }); test('test state of globally enabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledGlobally)); }); test('test disable an extension for workspace', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceDisabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledWorkspace); }); test('test disable an extension for workspace returns a truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(value => assert.ok(value)); }); test('test disable an extension for workspace again should return a falsy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) .then(value => assert.ok(!value[0])); }); test('test state of workspace disabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledWorkspace)); }); test('test state of workspace and globally disabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledWorkspace)); }); test('test state of workspace enabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceEnabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledWorkspace)); }); test('test state of globally disabled and workspace enabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceEnabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledWorkspace)); }); test('test state of an extension when disabled for workspace from workspace enabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledWorkspace)); }); test('test state of an extension when disabled globally from workspace enabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledGlobally)); }); test('test state of an extension when disabled globally from workspace disabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledGlobally)); }); test('test state of an extension when enabled globally from workspace enabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledGlobally)); }); test('test state of an extension when enabled globally from workspace disabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledGlobally)); }); test('test disable an extension for workspace and then globally', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Disabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledGlobally); }); test('test disable an extension for workspace and then globally return a truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) .then(value => assert.ok(value)); }); test('test disable an extension for workspace and then globally trigger the change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -218,23 +230,23 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally and then for workspace', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceDisabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledWorkspace); }); test('test disable an extension globally and then for workspace return a truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) .then(value => assert.ok(value)); }); test('test disable an extension globally and then for workspace triggers the change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -243,29 +255,29 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension for workspace when there is no workspace throws error', () => { instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(() => assert.fail('should throw an error'), error => assert.ok(error)); }); test('test enable an extension globally', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.Enabled); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.EnabledGlobally); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); test('test enable an extension globally return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) .then(value => assert.ok(value)); }); test('test enable an extension globally triggers change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -273,29 +285,29 @@ suite('ExtensionEnablementService Test', () => { }); test('test enable an extension globally when already enabled return falsy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally) .then(value => assert.ok(!value[0])); }); test('test enable an extension for workspace', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceEnabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceEnabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledWorkspace); }); test('test enable an extension for workspace return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) .then(value => assert.ok(value)); }); test('test enable an extension for workspace triggers change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.DisabledWorkspace) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.WorkspaceEnabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.EnabledWorkspace)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.b' }); @@ -303,48 +315,48 @@ suite('ExtensionEnablementService Test', () => { }); test('test enable an extension for workspace when already enabled return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace) .then(value => assert.ok(value)); }); test('test enable an extension for workspace when disabled in workspace and gloablly', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceEnabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceEnabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledWorkspace); }); test('test enable an extension globally when disabled in workspace and gloablly', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceEnabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.Enabled); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.EnabledGlobally); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); test('test installing an extension re-eanbles it when disabled globally', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); assert.ok(testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(local), EnablementState.EnabledGlobally); }); test('test updating an extension does not re-eanbles it when disabled globally', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.Disabled); + assert.equal(testObject.getEnablementState(local), EnablementState.DisabledGlobally); }); test('test installing an extension fires enablement change event when disabled globally', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); return new Promise((c, e) => { testObject.onEnablementChanged(([e]) => { if (e.identifier.id === local.identifier.id) { @@ -358,7 +370,7 @@ suite('ExtensionEnablementService Test', () => { test('test updating an extension does not fires enablement change event when disabled globally', async () => { const target = sinon.spy(); const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); testObject.onEnablementChanged(target); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!target.called); @@ -366,23 +378,23 @@ suite('ExtensionEnablementService Test', () => { test('test installing an extension re-eanbles it when workspace disabled', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); assert.ok(testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(local), EnablementState.EnabledGlobally); }); test('test updating an extension does not re-eanbles it when workspace disabled', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.WorkspaceDisabled); + assert.equal(testObject.getEnablementState(local), EnablementState.DisabledWorkspace); }); test('test installing an extension fires enablement change event when workspace disabled', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); return new Promise((c, e) => { testObject.onEnablementChanged(([e]) => { if (e.identifier.id === local.identifier.id) { @@ -396,7 +408,7 @@ suite('ExtensionEnablementService Test', () => { test('test updating an extension does not fires enablement change event when workspace disabled', async () => { const target = sinon.spy(); const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); testObject.onEnablementChanged(target); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!target.called); @@ -412,26 +424,26 @@ suite('ExtensionEnablementService Test', () => { test('test remove an extension from disablement list when uninstalled', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); didUninstallEvent.fire({ identifier: { id: 'pub.a' } }); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); test('test isEnabled return false extension is disabled globally', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => assert.ok(!testObject.isEnabled(aLocalExtension('pub.a')))); }); test('test isEnabled return false extension is disabled in workspace', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(() => assert.ok(!testObject.isEnabled(aLocalExtension('pub.a')))); }); test('test isEnabled return true extension is not disabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.c')], EnablementState.Disabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.c')], EnablementState.DisabledGlobally)) .then(() => assert.ok(testObject.isEnabled(aLocalExtension('pub.b')))); }); @@ -471,22 +483,109 @@ suite('ExtensionEnablementService Test', () => { instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([extension, aLocalExtension('pub.b')]) } as IExtensionManagementService); testObject = new TestExtensionEnablementService(instantiationService); assert.ok(!testObject.isEnabled(extension)); - assert.deepEqual(testObject.getEnablementState(extension), EnablementState.Disabled); + assert.deepEqual(testObject.getEnablementState(extension), EnablementState.DisabledByEnvironemt); + }); + + test('test local workspace extension is disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(!testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.DisabledByExtensionKind); + }); + + test('test local ui extension is not disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.EnabledGlobally); + }); + + test('test canChangeEnablement return false when the local workspace extension is disabled by kind', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), false); + }); + + test('test canChangeEnablement return true for local ui extension', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), true); + }); + + test('test remote ui extension is disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(!testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.DisabledByExtensionKind); + }); + + test('test remote workspace extension is not disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.EnabledGlobally); + }); + + test('test canChangeEnablement return false when the remote ui extension is disabled by kind', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), false); + }); + + test('test canChangeEnablement return true for remote workspace extension', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), true); }); }); +function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService): IExtensionManagementServerService { + const localExtensionManagementServer = { + authority: 'vscode-local', + label: 'local', + extensionManagementService: instantiationService.get(IExtensionManagementService) + }; + const remoteExtensionManagementServer = { + authority: 'vscode-remote', + label: 'remote', + extensionManagementService: instantiationService.get(IExtensionManagementService) + }; + return { + _serviceBrand: {}, + localExtensionManagementServer, + remoteExtensionManagementServer, + getExtensionManagementServer: (location: URI) => { + if (location.scheme === Schemas.file) { + return localExtensionManagementServer; + } + if (location.scheme === REMOTE_HOST_SCHEME) { + return remoteExtensionManagementServer; + } + return null; + } + }; +} + function aLocalExtension(id: string, contributes?: IExtensionContributions, type?: ExtensionType): ILocalExtension { + return aLocalExtension2(id, contributes ? { contributes } : {}, isUndefinedOrNull(type) ? {} : { type }); +} + +function aLocalExtension2(id: string, manifest: any = {}, properties: any = {}): ILocalExtension { const [publisher, name] = id.split('.'); - type = isUndefinedOrNull(type) ? ExtensionType.User : type; - return Object.create({ + properties = assign({ identifier: { id }, galleryIdentifier: { id, uuid: undefined }, - manifest: { - name, - publisher, - contributes - }, - type - }); + type: ExtensionType.User + }, properties); + manifest = assign({ name, publisher }, manifest); + return Object.create({ manifest, ...properties }); } diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index de1dcd86b5..bfe24dcb4a 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 18657a637b..886da1e35d 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -10,7 +10,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import * as perf from 'vs/base/common/performance'; import { isEqualOrParent } from 'vs/base/common/resources'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index e82f6fb6bf..e4cee39752 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -8,7 +8,8 @@ import { Action } from 'vs/base/common/actions'; import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { EnablementState, IExtensionEnablementService, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { INotificationHandle, INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -190,7 +191,7 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return; } - await this.extensionEnablementService.setEnablement([extension], EnablementState.Enabled); + await this.extensionEnablementService.setEnablement([extension], EnablementState.EnabledGlobally); await this.reloadAndHandle(uri); } } diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts index f61554294d..9c4bf65afb 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -24,7 +24,7 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IProductService } from 'vs/platform/product/common/product'; import { ISignService } from 'vs/platform/sign/common/sign'; diff --git a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts index b82afa42ad..2a16c37dfd 100644 --- a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts @@ -15,7 +15,7 @@ import { originalFSPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import pkg from 'vs/platform/product/node/package'; import product from 'vs/platform/product/node/product'; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 4b286efbe7..e352f7d1f7 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -35,7 +35,7 @@ import { withNullAsUndefined } from 'vs/base/common/types'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { parseExtensionDevOptions } from '../common/extensionDevOptions'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions'; import { isEqualOrParent } from 'vs/base/common/resources'; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts index e9208fa528..4d93e4cae2 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts @@ -3,128 +3,17 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Event, Emitter } from 'vs/base/common/event'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IExtensionHostDebugService, IAttachSessionEvent, ITerminateSessionEvent, ILogToSessionEvent, IReloadSessionEvent, ICloseSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { IRemoteConsoleLog } from 'vs/base/common/console'; -import { ipcRenderer as ipc } from 'electron'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; -interface IReloadBroadcast extends IReloadSessionEvent { - type: 'vscode:extensionReload'; -} - -interface IAttachSessionBroadcast extends IAttachSessionEvent { - type: 'vscode:extensionAttach'; -} - -interface ICloseBroadcast extends ICloseSessionEvent { - type: 'vscode:extensionCloseExtensionHost'; -} - -interface ILogToSessionBroadcast extends ILogToSessionEvent { - type: 'vscode:extensionLog'; -} - -interface ITerminateSessionBroadcast extends ITerminateSessionEvent { - type: 'vscode:extensionTerminate'; -} - -const CHANNEL = 'vscode:extensionHostDebug'; - -class ExtensionHostDebugService implements IExtensionHostDebugService { - _serviceBrand: any; - - private windowId: number; - private readonly _onReload = new Emitter(); - private readonly _onClose = new Emitter(); - private readonly _onAttachSession = new Emitter(); - private readonly _onLogToSession = new Emitter(); - private readonly _onTerminateSession = new Emitter(); +export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient { constructor( - @IWindowService readonly windowService: IWindowService, + @IMainProcessService readonly windowService: IMainProcessService, ) { - this.windowId = windowService.windowId; - - ipc.on(CHANNEL, (_: unknown, broadcast: IReloadBroadcast | ICloseBroadcast | IAttachSessionBroadcast | ILogToSessionBroadcast | ITerminateSessionBroadcast) => { - switch (broadcast.type) { - case 'vscode:extensionReload': - this._onReload.fire(broadcast); - break; - case 'vscode:extensionCloseExtensionHost': - this._onClose.fire(broadcast); - break; - case 'vscode:extensionAttach': - this._onAttachSession.fire(broadcast); - break; - case 'vscode:extensionLog': - this._onLogToSession.fire(broadcast); - break; - case 'vscode:extensionTerminate': - this._onTerminateSession.fire(broadcast); - break; - } - }); - } - - reload(sessionId: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionReload', - sessionId - }); - } - - get onReload(): Event { - return this._onReload.event; - } - - close(sessionId: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionCloseExtensionHost', - sessionId - }); - } - - get onClose(): Event { - return this._onClose.event; - } - - attachSession(sessionId: string, port: number, subId?: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionAttach', - sessionId, - port, - subId - }); - } - - get onAttachSession(): Event { - return this._onAttachSession.event; - } - - logToSession(sessionId: string, log: IRemoteConsoleLog): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionLog', - sessionId, - log - }); - } - - get onLogToSession(): Event { - return this._onLogToSession.event; - } - - terminateSession(sessionId: string, subId?: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionTerminate', - sessionId, - subId - }); - } - - get onTerminateSession(): Event { - return this._onTerminateSession.event; + super(windowService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); } } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 6173dc662c..ea2c188a24 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -14,7 +14,8 @@ import * as path from 'vs/base/common/path'; import { runWhenIdle } from 'vs/base/common/async'; import { URI } from 'vs/base/common/uri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionEnablementService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; diff --git a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts index cfd019527e..8366a02073 100644 --- a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts +++ b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts @@ -18,7 +18,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { localize } from 'vs/nls'; import { IProductService } from 'vs/platform/product/common/product'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; export class RemoteExtensionManagementChannelClient extends ExtensionManagementChannelClient { diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 5bb8732e6f..4ba29a31a3 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import * as json from 'vs/base/common/json'; import * as arrays from 'vs/base/common/arrays'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts new file mode 100644 index 0000000000..03d1a1d5c0 --- /dev/null +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; +import { NullTelemetryService, combinedAppender, LogAppender, ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { ILogService } from 'vs/platform/log/common/log'; +import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/browser/workbenchCommonProperties'; +import { IProductService } from 'vs/platform/product/common/product'; + +interface IConfig { + instrumentationKey?: string; + endpointUrl?: string; + emitLineDelimitedJson?: boolean; + accountId?: string; + sessionRenewalMs?: number; + sessionExpirationMs?: number; + maxBatchSizeInBytes?: number; + maxBatchInterval?: number; + enableDebug?: boolean; + disableExceptionTracking?: boolean; + disableTelemetry?: boolean; + verboseLogging?: boolean; + diagnosticLogInterval?: number; + samplingPercentage?: number; + autoTrackPageVisitTime?: boolean; + disableAjaxTracking?: boolean; + overridePageViewDuration?: boolean; + maxAjaxCallsPerView?: number; + disableDataLossAnalysis?: boolean; + disableCorrelationHeaders?: boolean; + correlationHeaderExcludedDomains?: string[]; + disableFlushOnBeforeUnload?: boolean; + enableSessionStorageBuffer?: boolean; + isCookieUseDisabled?: boolean; + cookieDomain?: string; + isRetryDisabled?: boolean; + url?: string; + isStorageUseDisabled?: boolean; + isBeaconApiDisabled?: boolean; + sdkExtension?: string; + isBrowserLinkTrackingEnabled?: boolean; + appId?: string; + enableCorsCorrelation?: boolean; +} + +declare class Microsoft { + public static ApplicationInsights: { + Initialization: { + new(init: { config: IConfig }): AppInsights; + } + }; +} + +declare interface IAppInsightsClient { + config: IConfig; + + /** Log a user action or other occurrence. */ + trackEvent: (name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number }) => void; + + /** Immediately send all queued telemetry. Synchronous. */ + flush(): void; +} + +interface AppInsights { + loadAppInsights: () => IAppInsightsClient; +} + +export class WebTelemetryAppender implements ITelemetryAppender { + private _aiClient?: IAppInsightsClient; + + constructor(aiKey: string, private _logService: ILogService) { + const initConfig = { + config: { + instrumentationKey: aiKey, + endpointUrl: 'https://vortex.data.microsoft.com/collect/v1', + emitLineDelimitedJson: true, + autoTrackPageVisitTime: false, + disableExceptionTracking: true, + disableAjaxTracking: true + } + }; + + const appInsights = new Microsoft.ApplicationInsights.Initialization(initConfig); + this._aiClient = appInsights.loadAppInsights(); + } + + log(eventName: string, data: any): void { + if (!this._aiClient) { + return; + } + + data = validateTelemetryData(data); + this._logService.trace(`telemetry/${eventName}`, data); + + this._aiClient.trackEvent('monacoworkbench/' + eventName, data.properties, data.measurements); + } + + dispose(): Promise | undefined { + if (this._aiClient) { + return new Promise(resolve => { + this._aiClient!.flush(); + this._aiClient = undefined; + resolve(undefined); + }); + } + + return undefined; + } +} + +export class TelemetryService extends Disposable implements ITelemetryService { + + _serviceBrand: any; + + private impl: ITelemetryService; + + constructor( + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @ILogService logService: ILogService, + @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService, + @IProductService productService: IProductService + ) { + super(); + + const aiKey = productService.aiConfig && productService.aiConfig.asimovKey; + if (!environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!productService.enableTelemetry && !!aiKey) { + const config: ITelemetryServiceConfig = { + appender: combinedAppender(new WebTelemetryAppender(aiKey, logService), new LogAppender(logService)), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.configuration.remoteAuthority), + piiPaths: [environmentService.appRoot] + }; + + this.impl = this._register(new BaseTelemetryService(config, configurationService)); + } else { + this.impl = NullTelemetryService; + } + } + + setEnabled(value: boolean): void { + return this.impl.setEnabled(value); + } + + get isOptedIn(): boolean { + return this.impl.isOptedIn; + } + + publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise { + return this.impl.publicLog(eventName, data, anonymizeFilePaths); + } + + publicLog2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck, anonymizeFilePaths?: boolean) { + return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths); + } + + getTelemetryInfo(): Promise { + return this.impl.getTelemetryInfo(); + } +} + +registerSingleton(ITelemetryService, TelemetryService); \ No newline at end of file diff --git a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index 419c2f0423..91e12fbf2f 100644 --- a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -39,7 +39,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const config: ITelemetryServiceConfig = { appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)), commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), - piiPaths: [environmentService.appRoot, environmentService.extensionsPath] + piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot] }; this.impl = this._register(new BaseTelemetryService(config, configurationService)); diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index ff1e4ea829..d4bae700c1 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -65,7 +65,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { AccessibilityService } from 'vs/workbench/services/accessibility/node/accessibilityService'; -import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; @@ -125,12 +125,11 @@ import 'vs/workbench/services/textfile/common/textResourcePropertiesService'; import 'vs/workbench/services/mode/common/workbenchModeService'; import 'vs/workbench/services/commands/common/commandService'; import 'vs/workbench/services/themes/browser/workbenchThemeService'; -import 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; import 'vs/workbench/services/extensions/electron-browser/extensionService'; import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; -import 'vs/workbench/services/extensions/node/multiExtensionManagement'; import 'vs/workbench/services/label/common/labelService'; -import 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/window/electron-browser/windowService'; @@ -138,8 +137,9 @@ import 'vs/workbench/services/telemetry/electron-browser/telemetryService'; import 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/node/extensionManagementService'; - +registerSingleton(IExtensionManagementService, ExtensionManagementService); registerSingleton(IBackupFileService, BackupFileService); registerSingleton(IMenuService, MenuService, true); registerSingleton(IListService, ListService, true); @@ -366,6 +366,7 @@ import 'vs/workbench/contrib/webview/browser/webview.contribution'; import 'vs/workbench/contrib/webview/electron-browser/webview.contribution'; // Extensions Management +import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; import 'vs/workbench/contrib/extensions/electron-browser/extensions.contribution'; import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 69ec7383b1..04f25a0234 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -63,7 +63,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; -import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService'; @@ -73,8 +73,6 @@ import { DialogService } from 'vs/platform/dialogs/browser/dialogService'; // import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; // import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService'; // import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -// import { IProductService } from 'vs/platform/product/common/product'; -// import { ProductService } from 'vs/platform/product/node/productService'; // import { IWindowsService } from 'vs/platform/windows/common/windows'; // import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; // import { IUpdateService } from 'vs/platform/update/common/update'; @@ -120,24 +118,25 @@ import 'vs/workbench/services/textfile/common/textResourcePropertiesService'; import 'vs/workbench/services/mode/common/workbenchModeService'; import 'vs/workbench/services/commands/common/commandService'; import 'vs/workbench/services/themes/browser/workbenchThemeService'; -// import 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; import 'vs/workbench/services/extensions/browser/extensionService'; // import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; -// import 'vs/workbench/services/extensions/node/multiExtensionManagement'; import 'vs/workbench/services/label/common/labelService'; -// import 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; // import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import 'vs/workbench/services/notification/common/notificationService'; // import 'vs/workbench/services/window/electron-browser/windowService'; -// import 'vs/workbench/services/telemetry/electron-browser/telemetryService'; +import 'vs/workbench/services/telemetry/browser/telemetryService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; +import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; import 'vs/workbench/browser/web.simpleservices'; +registerSingleton(IExtensionManagementService, ExtensionManagementService); registerSingleton(IBackupFileService, BackupFileService); registerSingleton(IDialogService, DialogService, true); registerSingleton(IMenuService, MenuService, true); @@ -262,9 +261,9 @@ registerSingleton(IWebviewService, WebviewService, true); registerSingleton(IWebviewEditorService, WebviewEditorService, true); // Extensions Management -// import 'vs/workbench/contrib/extensions/electron-browser/extensions.contribution'; -// import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; -// import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; +import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; +import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; +import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; // Output Panel import 'vs/workbench/contrib/output/browser/output.contribution'; diff --git a/yarn.lock b/yarn.lock index 2a40d581fa..3751bf6d8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3870,10 +3870,10 @@ growl@1.9.2: resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= -gulp-atom-electron@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/gulp-atom-electron/-/gulp-atom-electron-1.20.0.tgz#10b01f6a4c0257a8468c4da4ec9c67ecb28a32ed" - integrity sha512-gs7xvZvq8Mq60+DmbfCeXZnhqhOaJa/wrctix0RP/lCfSgusJnBTBssC6er1JIiqdHmQ8zFiYaYZh41mdG36kQ== +gulp-atom-electron@^1.21.1: + version "1.21.1" + resolved "https://registry.yarnpkg.com/gulp-atom-electron/-/gulp-atom-electron-1.21.1.tgz#4017144bf659fbbf7d0644664fcc47c64efac0f0" + integrity sha512-UHEf2pZrJD/u+AAzKCbhdPXaKrReFDa+OEJjBCAdN2SHnD+dfZqSJAz/u2OD6YR/eREuUbQOCw+VWUwex20klQ== dependencies: event-stream "3.3.4" github-releases-ms "^0.5.0" @@ -6126,11 +6126,6 @@ nan@2.14.0, nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== -nan@^2.10.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" - integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw== - nan@^2.12.1: version "2.12.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" @@ -8217,6 +8212,11 @@ semver-greatest-satisfied-range@^1.1.0: dependencies: sver-compat "^1.5.0" +semver-umd@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" + integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== + "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -9902,10 +9902,10 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.3.1.tgz#51fb93debcd0c18a8b90dbc37f84f94333d0c486" - integrity sha512-4WLB/n4ZeWNi5AEzPTkfYrqbKtXlv0SlgmxbRVdulwZzGx/lfWeWPu9Shy32orM27IofQAQDuirbRBOYNJVzBA== +vscode-ripgrep@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.4.tgz#dae1c3eef350513299341cdf96e622c00b548eff" + integrity sha512-Bs8SvFAkR0QHf09J46VgNo19yRikOtj/f0zHzK3AM3ICjCGNN/BNoG9of6zGVHUTO+6Mk1RbKglyOHLKr8D1lg== vscode-sqlite3@4.0.8: version "4.0.8" @@ -10066,18 +10066,18 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -windows-foreground-love@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/windows-foreground-love/-/windows-foreground-love-0.1.0.tgz#948e4beac0733cd58624710cc09432b7e8bf3521" - integrity sha1-lI5L6sBzPNWGJHEMwJQyt+i/NSE= +windows-foreground-love@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/windows-foreground-love/-/windows-foreground-love-0.2.0.tgz#b291832d8a02a966bc046ba0e498cc789809076b" + integrity sha512-72ZDshnt8Q3/ImLMt4wxsY8eVnUd1KDb5QfvZX09AxJJJa0hGdyzPfd/ms0pKSYYwKlEhB1ri+WDKNvdIpJknQ== -windows-mutex@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/windows-mutex/-/windows-mutex-0.2.1.tgz#05a8da8018f22874d7fbbd775c0141876d1c28fc" - integrity sha512-TaLGQa+qBcPZ2EH94BD/3Hy8fycrZjzqxI/lOMdXPyvffNnIJOvKwEyvNRC25bVFQ2mliJBziKhCMEhk9Dhhhg== +windows-mutex@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/windows-mutex/-/windows-mutex-0.3.0.tgz#2f51a0c97b3979c98952b23c086035f1f3715fab" + integrity sha512-IDWzyHOEpQr7m590pT90jMbCYNe525d7BgP6F80TjispEu2gWMvTIoSuO6Sy4atIEhvs3ys7DVlKdLzIAyRviQ== dependencies: bindings "^1.2.1" - nan "^2.10.0" + nan "^2.14.0" windows-process-tree@0.2.4: version "0.2.4"