diff --git a/.github/classifier.yml b/.github/classifier.yml index 330cc3d0aa1..29f9fa41f52 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -18,40 +18,127 @@ assignees: [ weinand ], assignLabel: false }, - diff-editor: [], - dropdown: [], - editor: { + diff-editor: : { + assignees: [], + assignLabel: false + }, + dropdown: [], + editor: : { + assignees: [], + assignLabel: false + }, + editor-1000-limit: : { + assignees: [], + assignLabel: false + }, + editor-autoclosing: : { + assignees: [], + assignLabel: false + }, + editor-autoindent: : { + assignees: [], + assignLabel: false + }, + editor-brackets: : { + assignees: [], + assignLabel: false + }, + editor-clipboard: : { + assignees: [], + assignLabel: false + }, + editor-code-actions: : { + assignees: [], + assignLabel: false + }, + editor-code-lens: : { + assignees: [], + assignLabel: false + }, + editor-color-picker: : { + assignees: [], + assignLabel: false + }, + editor-colors: : { + assignees: [], + assignLabel: false + }, + editor-columnselect: : { + assignees: [], + assignLabel: false + }, + editor-commands: : { + assignees: [], + assignLabel: false + }, + editor-contrib: : { + assignees: [], + assignLabel: false + }, + editor-drag-and-drop: : { + assignees: [], + assignLabel: false + }, + editor-find: : { + assignees: [], + assignLabel: false + }, + editor-folding: : { + assignees: [], + assignLabel: false + }, + editor-hover: : { + assignees: [], + assignLabel: false + }, + editor-ime: : { + assignees: [], + assignLabel: false + }, + editor-input: : { + assignees: [], + assignLabel: false + }, + editor-ligatures: : { + assignees: [], + assignLabel: false + }, + editor-links: : { + assignees: [], + assignLabel: false + }, + editor-minimap: : { + assignees: [], + assignLabel: false + }, + editor-multicursor: : { + assignees: [], + assignLabel: false + }, + editor-parameter-hints: : { + assignees: [], + assignLabel: false + }, + editor-rendering: : { + assignees: [], + assignLabel: false + }, + editor-smooth: : { + assignees: [], + assignLabel: false + }, + editor-symbols: : { + assignees: [], + assignLabel: false + }, + editor-textbuffer: : { + assignees: [], + assignLabel: false + }, + editor-wrapping: : { assignees: [], assignLabel: false }, - editor-1000-limit: [], - editor-autoclosing: [], - editor-autoindent: [], - editor-brackets: [], - editor-clipboard: [], - editor-code-actions: [], - editor-code-lens: [], - editor-color-picker: [], - editor-colors: [], - editor-columnselect: [], - editor-commands: [], - editor-contrib: [], - editor-drag-and-drop: [], - editor-find: [], - editor-folding: [], - editor-hover: [], - editor-ime: [], - editor-input: [], - editor-ligatures: [], - editor-links: [], - editor-minimap: [], - editor-multicursor: [], - editor-parameter-hints: [], - editor-rendering: [], - editor-smooth: [], - editor-symbols: [], - editor-textbuffer: [], - editor-wrapping: [], emmet: [ octref ], error-list: [], explorer-custom: [], @@ -81,14 +168,20 @@ hot-exit: [], html: [], install-update: [], - integrated-terminal: [ Tyriar ], + integrated-terminal: [], integration-test: [], intellisense-config: [], issue-reporter: [ RMacfarlane ], javascript: [ mjbvz ], json: [], - keyboard-layout: [], - keybindings: [], + keyboard-layout: : { + assignees: [], + assignLabel: false + }, + keybindings: : { + assignees: [], + assignLabel: false + }, keybindings-editor: [], lang-diagnostics: [], languages basic: [], diff --git a/.gitignore b/.gitignore index 68834eb43ad..160c42ed74b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,9 +18,11 @@ out-vscode-min/ out-vscode-reh/ out-vscode-reh-min/ out-vscode-reh-pkg/ +out-vscode-reh-web/ +out-vscode-reh-web-min/ +out-vscode-reh-web-pkg/ out-vscode-web/ out-vscode-web-min/ -out-vscode-web-pkg/ src/vs/server resources/server build/node_modules diff --git a/.vscode/settings.json b/.vscode/settings.json index 3fa04b1ee95..1a760bdda6b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,5 +59,6 @@ "git.ignoreLimitWarning": true, "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" - } -} + }, + "files.insertFinalNewline": true +} \ No newline at end of file diff --git a/.yarnrc b/.yarnrc index 441b5a2e69a..c45abdbacad 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "4.2.5" +target "4.2.7" runtime "electron" diff --git a/build/.cachesalt b/build/.cachesalt index 56a6051ca2b..105ce86ae3c 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -1 \ No newline at end of file +2019-07-11T05:47:05.444Z diff --git a/build/azure-pipelines/common/extract-telemetry.sh b/build/azure-pipelines/common/extract-telemetry.sh index 916c87c82ce..84bbd9c537c 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 00000000000..fcba1e042ba --- /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/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index d8b2c009c4a..b712e072849 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -6,8 +6,8 @@ steps: - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '.build/commit' - targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' vstsFeed: 'npm-vscode' platformIndependent: true alias: 'Compilation' @@ -89,9 +89,7 @@ steps: VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ yarn gulp vscode-reh-darwin-min-ci VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-web-darwin-min-ci - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - yarn gulp upload-vscode-sourcemaps + yarn gulp vscode-reh-web-darwin-min-ci displayName: Build - script: | diff --git a/build/azure-pipelines/darwin/publish.sh b/build/azure-pipelines/darwin/publish.sh index 6bc80ce04e8..fa453bcaff5 100755 --- a/build/azure-pipelines/darwin/publish.sh +++ b/build/azure-pipelines/darwin/publish.sh @@ -30,7 +30,7 @@ node build/azure-pipelines/common/publish.js \ ../vscode-server-darwin.zip # publish hockeyapp symbols -node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS" +node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS" # upload configuration yarn gulp upload-vscode-configuration diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index 4057894f025..62ee67ad1c6 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -31,12 +31,12 @@ steps: git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" git fetch distro - # Push master branch into master and oss/master - git push distro origin/master:refs/heads/master origin/master:refs/heads/oss/master + # Push master branch into oss/master + git push distro origin/master:refs/heads/oss/master # Push every release branch into oss/release git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro git merge $(node -p "require('./package.json').distro") - displayName: Sync & Merge Distro \ No newline at end of file + displayName: Sync & Merge Distro diff --git a/build/azure-pipelines/linux/product-build-linux-multiarch.yml b/build/azure-pipelines/linux/product-build-linux-multiarch.yml index c4e1e05e502..dff5ae2ceaf 100644 --- a/build/azure-pipelines/linux/product-build-linux-multiarch.yml +++ b/build/azure-pipelines/linux/product-build-linux-multiarch.yml @@ -6,8 +6,8 @@ steps: - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '.build/commit' - targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' vstsFeed: 'npm-vscode' platformIndependent: true alias: 'Compilation' diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 76c86e32323..e97f5cfdeff 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -6,8 +6,8 @@ steps: - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '.build/commit' - targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' vstsFeed: 'npm-vscode' platformIndependent: true alias: 'Compilation' @@ -34,8 +34,6 @@ steps: - script: | set -e - export npm_config_arch="$(VSCODE_ARCH)" - cat << EOF > ~/.netrc machine github.com login vscode @@ -86,22 +84,22 @@ steps: - script: | set -e VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-linux-$VSCODE_ARCH-min-ci + yarn gulp vscode-linux-x64-min-ci VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-reh-linux-$VSCODE_ARCH-min-ci + yarn gulp vscode-reh-linux-x64-min-ci VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - yarn gulp vscode-web-linux-$VSCODE_ARCH-min-ci + yarn gulp vscode-reh-web-linux-x64-min-ci displayName: Build - script: | set -e - yarn gulp "electron-$(VSCODE_ARCH)" + yarn gulp "electron-x64" # xvfb seems to be crashing often, let's make sure it's always up service xvfb start DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" - # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)" + # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64" displayName: Run unit tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) @@ -117,7 +115,7 @@ steps: - task: PublishPipelineArtifact@0 displayName: 'Publish Pipeline Artifact' inputs: - artifactName: snap-$(VSCODE_ARCH) + artifactName: snap-x64 targetPath: .build/linux/snap-tarball - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 diff --git a/build/azure-pipelines/linux/publish.sh b/build/azure-pipelines/linux/publish.sh index a6b48389d58..5fc86d02d60 100755 --- a/build/azure-pipelines/linux/publish.sh +++ b/build/azure-pipelines/linux/publish.sh @@ -4,7 +4,7 @@ REPO="$(pwd)" ROOT="$REPO/.." # Publish tarball -PLATFORM_LINUX="linux-$VSCODE_ARCH" +PLATFORM_LINUX="linux-x64" BUILDNAME="VSCode-$PLATFORM_LINUX" BUILD="$ROOT/$BUILDNAME" BUILD_VERSION="$(date +%s)" @@ -19,24 +19,22 @@ rm -rf $ROOT/code-*.tar.* node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH" # Publish Remote Extension Host -if [[ "$VSCODE_ARCH" != "ia32" ]]; then - LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX" - SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX" - SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz" - SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" +LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX" +SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX" +SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz" +SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" - rm -rf $ROOT/vscode-server-*.tar.* - (cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) +rm -rf $ROOT/vscode-server-*.tar.* +(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) - node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH" -fi +node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH" # Publish hockeyapp symbols -node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64" +node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64" # Publish DEB -yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb" -PLATFORM_DEB="linux-deb-$VSCODE_ARCH" +yarn gulp "vscode-linux-x64-build-deb" +PLATFORM_DEB="linux-deb-x64" DEB_ARCH="amd64" DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)" DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME" @@ -44,8 +42,8 @@ DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME" node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH" # Publish RPM -yarn gulp "vscode-linux-$VSCODE_ARCH-build-rpm" -PLATFORM_RPM="linux-rpm-$VSCODE_ARCH" +yarn gulp "vscode-linux-x64-build-rpm" +PLATFORM_RPM="linux-rpm-x64" RPM_ARCH="x86_64" RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)" RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME" @@ -53,10 +51,10 @@ RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME" node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH" # Publish Snap -yarn gulp "vscode-linux-$VSCODE_ARCH-prepare-snap" +yarn gulp "vscode-linux-x64-prepare-snap" # Pack snap tarball artifact, in order to preserve file perms mkdir -p $REPO/.build/linux/snap-tarball -SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$VSCODE_ARCH.tar.gz" +SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz" rm -rf $SNAP_TARBALL_PATH (cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap) diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index 9dbe920b87b..4c3f602e8ce 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -16,7 +16,7 @@ steps: - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact' inputs: - artifactName: snap-$(VSCODE_ARCH) + artifactName: snap-x64 targetPath: .build/linux/snap-tarball - script: | @@ -31,14 +31,13 @@ steps: # Define variables REPO="$(pwd)" - ARCH="$(VSCODE_ARCH)" - SNAP_ROOT="$REPO/.build/linux/snap/$ARCH" + SNAP_ROOT="$REPO/.build/linux/snap/x64" # Install build dependencies (cd build && yarn) # Unpack snap tarball artifact, in order to preserve file perms - SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$ARCH.tar.gz" + SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz" (cd .build/linux && tar -xzf $SNAP_TARBALL_PATH) # Create snap package @@ -52,4 +51,4 @@ steps: # Publish snap package AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" \ No newline at end of file + node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-x64" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" \ No newline at end of file diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 666cfa07ca9..469494c7d58 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -10,15 +10,12 @@ jobs: - job: Compile pool: vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: x64 container: vscode-x64 steps: - template: product-compile.yml - job: Windows condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true')) - timeoutInMinutes: 120 pool: vmImage: VS2017-Win2016 variables: @@ -30,7 +27,6 @@ jobs: - job: Windows32 condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) - timeoutInMinutes: 120 pool: vmImage: VS2017-Win2016 variables: @@ -42,11 +38,8 @@ jobs: - job: Linux condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) - timeoutInMinutes: 120 pool: vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: x64 container: vscode-x64 dependsOn: - Compile @@ -55,11 +48,8 @@ jobs: - job: LinuxSnap condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) - timeoutInMinutes: 120 pool: vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: x64 container: snapcraft dependsOn: Linux steps: @@ -67,7 +57,6 @@ jobs: - job: LinuxArmhf condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) - timeoutInMinutes: 120 pool: vmImage: 'Ubuntu-16.04' variables: @@ -79,7 +68,6 @@ jobs: - job: LinuxAlpine condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) - timeoutInMinutes: 120 pool: vmImage: 'Ubuntu-16.04' variables: @@ -89,9 +77,19 @@ jobs: steps: - template: linux/product-build-linux-multiarch.yml +- job: LinuxWeb + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WEB'], 'true')) + pool: + vmImage: 'Ubuntu-16.04' + variables: + VSCODE_ARCH: x64 + dependsOn: + - Compile + steps: + - template: web/product-build-web.yml + - job: macOS condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true')) - timeoutInMinutes: 120 pool: vmImage: macOS 10.13 dependsOn: @@ -130,8 +128,8 @@ jobs: - template: sync-mooncake.yml schedules: -- cron: "0 6 * * Mon-Fri" - displayName: Mon-Fri at 6:00 +- cron: "0 5 * * Mon-Fri" + displayName: Mon-Fri at 7:00 branches: include: - master \ No newline at end of file diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 5b425f60fb6..e5105326e7b 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -6,8 +6,8 @@ steps: - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '.build/commit' - targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' vstsFeed: 'npm-vscode' platformIndependent: true alias: 'Compilation' @@ -31,8 +31,6 @@ steps: - script: | set -e - export npm_config_arch="$(VSCODE_ARCH)" - cat << EOF > ~/.netrc machine github.com login vscode @@ -105,14 +103,21 @@ steps: yarn gulp compile-extensions-build yarn gulp minify-vscode yarn gulp minify-vscode-reh - yarn gulp minify-vscode-web + yarn gulp minify-vscode-reh-web displayName: Compile condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) +- script: | + set -e + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + node build/azure-pipelines/upload-sourcemaps + displayName: Upload sourcemaps + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 inputs: - keyfile: '.build/commit' - targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' vstsFeed: 'npm-vscode' platformIndependent: true alias: 'Compilation' diff --git a/build/azure-pipelines/upload-sourcemaps.js b/build/azure-pipelines/upload-sourcemaps.js new file mode 100644 index 00000000000..ac3bd55a7f5 --- /dev/null +++ b/build/azure-pipelines/upload-sourcemaps.js @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const path = require('path'); +const es = require('event-stream'); +const azure = require('gulp-azure-storage'); +const vfs = require('vinyl-fs'); +const util = require('../lib/util'); +const root = path.dirname(path.dirname(__dirname)); +const commit = util.getVersion(root); + +function main() { + const vs = vfs.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only + .pipe(es.mapSync(f => { + f.path = `${f.base}/core/${f.relative}`; + return f; + })); + + const extensionsOut = vfs.src(['.build/extensions/**/*.js.map', '!**/node_modules/**'], { base: '.build' }); + + return es.merge(vs, extensionsOut) + .pipe(es.through(function (data) { + // debug + console.log('Uploading Sourcemap', data.relative); + this.emit('data', data); + })) + .pipe(azure.upload({ + account: process.env.AZURE_STORAGE_ACCOUNT, + key: process.env.AZURE_STORAGE_ACCESS_KEY, + container: 'sourcemaps', + prefix: commit + '/' + })); +} + +main(); \ No newline at end of file diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml new file mode 100644 index 00000000000..7c65dc982f0 --- /dev/null +++ b/build/azure-pipelines/web/product-build-web.yml @@ -0,0 +1,96 @@ +steps: +- script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: NodeTool@0 + inputs: + versionSpec: "10.15.1" + +- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.10.1" + +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + +- script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF + + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + +- script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro + +# - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 +# inputs: +# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' +# targetfolder: '**/node_modules, !**/node_modules/**/node_modules' +# vstsFeed: 'npm-vscode' + +- script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + # condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +# - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 +# inputs: +# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' +# targetfolder: '**/node_modules, !**/node_modules/**/node_modules' +# vstsFeed: 'npm-vscode' +# condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +# - script: | +# set -e +# yarn postinstall +# displayName: Run postinstall scripts +# condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + +- script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + +- script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-web-min-ci + displayName: Build + +- script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + ./build/azure-pipelines/web/publish.sh + displayName: Publish diff --git a/build/azure-pipelines/web/publish.sh b/build/azure-pipelines/web/publish.sh new file mode 100755 index 00000000000..9d662fcfe8b --- /dev/null +++ b/build/azure-pipelines/web/publish.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e +REPO="$(pwd)" +ROOT="$REPO/.." + +# Publish Web Client +WEB_BUILD_NAME="vscode-web" +WEB_TARBALL_FILENAME="vscode-web.tar.gz" +WEB_TARBALL_PATH="$ROOT/$WEB_TARBALL_FILENAME" + +rm -rf $ROOT/vscode-web.tar.* + +(cd $ROOT && tar --owner=0 --group=0 -czf $WEB_TARBALL_PATH $WEB_BUILD_NAME) + +node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "web-standalone" archive-unsigned "$WEB_TARBALL_FILENAME" "$VERSION" true "$WEB_TARBALL_PATH" diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index fc14cc0abec..66583616c6d 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -6,8 +6,8 @@ steps: - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '.build/commit' - targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' vstsFeed: 'npm-vscode' platformIndependent: true alias: 'Compilation' @@ -98,7 +98,7 @@ steps: $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } exec { yarn gulp "vscode-reh-win32-$env:VSCODE_ARCH-min-ci" } - exec { yarn gulp "vscode-web-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-reh-web-win32-$env:VSCODE_ARCH-min-ci" } exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } displayName: Build diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index f044a0e5384..a3483f451e2 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.28", + "version": "0.0.29", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 8828a0d394f..7085c4f8f50 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -17,7 +17,7 @@ const gunzip = require('gulp-gunzip'); const untar = require('gulp-untar'); const File = require('vinyl'); const fs = require('fs'); -const remote = require('gulp-remote-src'); +const remote = require('gulp-remote-retry-src'); const rename = require('gulp-rename'); const filter = require('gulp-filter'); const cp = require('child_process'); @@ -43,11 +43,11 @@ gulp.task('vscode-reh-linux-x64-min', noop); gulp.task('vscode-reh-linux-armhf-min', noop); gulp.task('vscode-reh-linux-alpine-min', noop); -gulp.task('vscode-web-win32-ia32-min', noop); -gulp.task('vscode-web-win32-x64-min', noop); -gulp.task('vscode-web-darwin-min', noop); -gulp.task('vscode-web-linux-x64-min', noop); -gulp.task('vscode-web-linux-alpine-min', noop); +gulp.task('vscode-reh-web-win32-ia32-min', noop); +gulp.task('vscode-reh-web-win32-x64-min', noop); +gulp.task('vscode-reh-web-darwin-min', noop); +gulp.task('vscode-reh-web-linux-x64-min', noop); +gulp.task('vscode-reh-web-linux-alpine-min', noop); function getNodeVersion() { const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 2d73433dfd6..99bd930a91c 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -63,7 +63,7 @@ const vscodeResources = [ 'out-build/bootstrap-amd.js', 'out-build/bootstrap-window.js', 'out-build/paths.js', - 'out-build/vs/**/*.{svg,png,cur,html}', + 'out-build/vs/**/*.{svg,png,html}', '!out-build/vs/code/browser/**/*.html', 'out-build/vs/base/common/performance.js', 'out-build/vs/base/node/languagePacks.js', @@ -77,8 +77,8 @@ const vscodeResources = [ 'out-build/vs/**/markdown.css', 'out-build/vs/workbench/contrib/tasks/**/*.json', 'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md', - 'out-build/vs/workbench/services/files/**/*.exe', - 'out-build/vs/workbench/services/files/**/*.md', + 'out-build/vs/platform/files/**/*.exe', + 'out-build/vs/platform/files/**/*.md', 'out-build/vs/code/electron-browser/workbench/**', 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js', 'out-build/vs/code/electron-browser/issue/issueReporter.js', @@ -86,12 +86,6 @@ const vscodeResources = [ '!**/test/**' ]; -const BUNDLED_FILE_HEADER = [ - '/*!--------------------------------------------------------', - ' * Copyright (C) Microsoft Corporation. All rights reserved.', - ' *--------------------------------------------------------*/' -].join('\n'); - const optimizeVSCodeTask = task.define('optimize-vscode', task.series( util.rimraf('out-vscode'), common.optimizeTask({ @@ -99,7 +93,6 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series( entryPoints: vscodeEntryPoints, resources: vscodeResources, loaderConfig: common.loaderConfig(nodeModules), - header: BUNDLED_FILE_HEADER, out: 'out-vscode', bundleInfo: undefined }) @@ -265,16 +258,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const src = gulp.src(out + '/**', { base: '.' }) .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); })) - .pipe(util.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); - - const root = path.resolve(path.join(__dirname, '..')); + .pipe(util.setExecutableBit(['**/*.sh'])); const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true }); - const sources = es.merge(src, extensions); + + const sources = es.merge(src, extensions) + .pipe(filter(['**', '!**/*.js.map'], { dot: true })); let version = packageJson.version; - // @ts-ignore JSON checking: quality is optional const quality = product.quality; if (quality && quality !== 'stable') { @@ -309,6 +300,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true }); + const root = path.resolve(path.join(__dirname, '..')); const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])); const deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) @@ -475,6 +467,8 @@ const apiToken = process.env.TRANSIFEX_API_TOKEN; gulp.task(task.define( 'vscode-translations-push', task.series( + compileBuildTask, + compileExtensionsBuildTask, optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; @@ -494,6 +488,8 @@ gulp.task(task.define( gulp.task(task.define( 'vscode-translations-export', task.series( + compileBuildTask, + compileExtensionsBuildTask, optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; @@ -531,32 +527,6 @@ gulp.task('vscode-translations-import', function () { })); }); -// Sourcemaps - -gulp.task('upload-vscode-sourcemaps', () => { - const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only - .pipe(es.mapSync(f => { - f.path = `${f.base}/core/${f.relative}`; - return f; - })); - - const extensionsOut = gulp.src(['extensions/**/out/**/*.map', '!extensions/**/node_modules/**'], { base: '.' }); - const extensionsDist = gulp.src(['extensions/**/dist/**/*.map', '!extensions/**/node_modules/**'], { base: '.' }); - - return es.merge(vs, extensionsOut, extensionsDist) - .pipe(es.through(function (data) { - // debug - console.log('Uploading Sourcemap', data.relative); - this.emit('data', data); - })) - .pipe(azure.upload({ - account: process.env.AZURE_STORAGE_ACCOUNT, - key: process.env.AZURE_STORAGE_ACCESS_KEY, - container: 'sourcemaps', - prefix: commit + '/' - })); -}); - // This task is only run for the MacOS build const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => { return new Promise((resolve, reject) => { diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js new file mode 100644 index 00000000000..11da75e482d --- /dev/null +++ b/build/gulpfile.vscode.web.js @@ -0,0 +1,151 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const gulp = require('gulp'); +const path = require('path'); +const es = require('event-stream'); +const util = require('./lib/util'); +const task = require('./lib/task'); +const common = require('./lib/optimize'); +const product = require('../product.json'); +const rename = require('gulp-rename'); +const filter = require('gulp-filter'); +const json = require('gulp-json-editor'); +const _ = require('underscore'); +const deps = require('./dependencies'); +const vfs = require('vinyl-fs'); +const packageJson = require('../package.json'); +const { compileBuildTask } = require('./gulpfile.compile'); + +const REPO_ROOT = path.dirname(__dirname); +const commit = util.getVersion(REPO_ROOT); +const BUILD_ROOT = path.dirname(REPO_ROOT); +const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web'); + +const productionDependencies = deps.getProductionDependencies(WEB_FOLDER); + +const nodeModules = Object.keys(product.dependencies || {}) + .concat(_.uniq(productionDependencies.map(d => d.name))); + +const vscodeWebResources = [ + + // Workbench + 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,html}', + 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', + 'out-build/vs/**/markdown.css', + + // Webview + 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', + + // Excludes + '!out-build/vs/**/{node,electron-browser,electron-main}/**', + '!out-build/vs/editor/standalone/**', + '!out-build/vs/workbench/**/*-tb.png', + '!**/test/**' +]; + +const buildfile = require('../src/buildfile'); + +const vscodeWebEntryPoints = [ + buildfile.workbenchWeb, + buildfile.serviceWorker, + buildfile.keyboardMaps, + buildfile.base +]; + +const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series( + util.rimraf('out-vscode-web'), + common.optimizeTask({ + src: 'out-build', + entryPoints: _.flatten(vscodeWebEntryPoints), + otherSources: [], + resources: vscodeWebResources, + loaderConfig: common.loaderConfig(nodeModules), + out: 'out-vscode-web', + bundleInfo: undefined + }) +)); + +const minifyVSCodeWebTask = task.define('minify-vscode-web', task.series( + optimizeVSCodeWebTask, + util.rimraf('out-vscode-web-min'), + common.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) +)); +gulp.task(minifyVSCodeWebTask); + +function packageTask(sourceFolderName, destinationFolderName) { + const destination = path.join(BUILD_ROOT, destinationFolderName); + + return () => { + const src = gulp.src(sourceFolderName + '/**', { base: '.' }) + .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); })) + .pipe(filter(['**', '!**/*.js.map'])); + + const sources = es.merge(src); + + let version = packageJson.version; + const quality = product.quality; + + if (quality && quality !== 'stable') { + version += '-' + quality; + } + + const name = product.nameShort; + const packageJsonStream = gulp.src(['remote/web/package.json'], { base: 'remote/web' }) + .pipe(json({ name, version })); + + const date = new Date().toISOString(); + + const productJsonStream = gulp.src(['product.json'], { base: '.' }) + .pipe(json({ commit, date })); + + const license = gulp.src(['remote/LICENSE'], { base: 'remote' }); + + const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(REPO_ROOT, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`])); + + const deps = gulp.src(dependenciesSrc, { base: 'remote/web', dot: true }) + .pipe(filter(['**', '!**/package-lock.json'])) + .pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore'))); + + const favicon = gulp.src('resources/server/favicon.ico', { base: 'resources/server' }); + + let all = es.merge( + packageJsonStream, + productJsonStream, + license, + sources, + deps, + favicon + ); + + let result = all + .pipe(util.skipDirectories()) + .pipe(util.fixWin32DirectoryPermissions()); + + return result.pipe(vfs.dest(destination)); + }; +} + +const dashed = (str) => (str ? `-${str}` : ``); + +['', 'min'].forEach(minified => { + const sourceFolderName = `out-vscode-web${dashed(minified)}`; + const destinationFolderName = `vscode-web`; + + const vscodeWebTaskCI = task.define(`vscode-web${dashed(minified)}-ci`, task.series( + minified ? minifyVSCodeWebTask : optimizeVSCodeWebTask, + util.rimraf(path.join(BUILD_ROOT, destinationFolderName)), + packageTask(sourceFolderName, destinationFolderName) + )); + gulp.task(vscodeWebTaskCI); + + const vscodeWebTask = task.define(`vscode-web${dashed(minified)}`, task.series( + compileBuildTask, + vscodeWebTaskCI + )); + gulp.task(vscodeWebTask); +}); \ No newline at end of file diff --git a/build/lib/extensions.js b/build/lib/extensions.js index e12f8f14568..73d2c7acef3 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -13,7 +13,7 @@ const File = require("vinyl"); const vsce = require("vsce"); const stats_1 = require("./stats"); const util2 = require("./util"); -const remote = require("gulp-remote-src"); +const remote = require("gulp-remote-retry-src"); const vzip = require('gulp-vinyl-zip'); const filter = require("gulp-filter"); const rename = require("gulp-rename"); @@ -111,12 +111,6 @@ function fromLocalWebpack(extensionPath) { data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) { return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; }), 'utf8'); - if (/\.js\.map$/.test(data.path)) { - if (!fs.existsSync(path.dirname(data.path))) { - fs.mkdirSync(path.dirname(data.path)); - } - fs.writeFileSync(data.path, data.contents); - } this.emit('data', data); })); }); @@ -195,20 +189,21 @@ function packageLocalExtensionsStream() { }) .filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => builtInExtensions.every(b => b.name !== name)); - return es.merge(gulp.src('extensions/node_modules/**', { base: '.' }), ...localExtensionDescriptions.map(extension => { + const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); + const localExtensions = localExtensionDescriptions.map(extension => { return fromLocal(extension.path) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })) - .pipe(util2.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + }); + return es.merge(nodeModules, ...localExtensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); } exports.packageLocalExtensionsStream = packageLocalExtensionsStream; function packageMarketplaceExtensionsStream() { - return es.merge(builtInExtensions.map(extension => { + const extensions = builtInExtensions.map(extension => { return fromMarketplace(extension.name, extension.version, extension.metadata) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })) - .pipe(util2.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + }); + return es.merge(extensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); } exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 381d56e2abb..4b185aff681 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -13,7 +13,7 @@ import * as File from 'vinyl'; import * as vsce from 'vsce'; import { createStatsStream } from './stats'; import * as util2 from './util'; -import remote = require('gulp-remote-src'); +import remote = require('gulp-remote-retry-src'); const vzip = require('gulp-vinyl-zip'); import filter = require('gulp-filter'); import rename = require('gulp-rename'); @@ -130,12 +130,6 @@ function fromLocalWebpack(extensionPath: string): Stream { return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; }), 'utf8'); - if (/\.js\.map$/.test(data.path)) { - if (!fs.existsSync(path.dirname(data.path))) { - fs.mkdirSync(path.dirname(data.path)); - } - fs.writeFileSync(data.path, data.contents); - } this.emit('data', data); })); }); @@ -237,22 +231,22 @@ export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream { .filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => builtInExtensions.every(b => b.name !== name)); - return es.merge( - gulp.src('extensions/node_modules/**', { base: '.' }), - ...localExtensionDescriptions.map(extension => { - return fromLocal(extension.path) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }) - ) - .pipe(util2.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); + const localExtensions = localExtensionDescriptions.map(extension => { + return fromLocal(extension.path) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + }); + + return es.merge(nodeModules, ...localExtensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); } export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream { - return es.merge(builtInExtensions.map(extension => { + const extensions = builtInExtensions.map(extension => { return fromMarketplace(extension.name, extension.version, extension.metadata) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })) - .pipe(util2.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + }); + + return es.merge(extensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); } diff --git a/build/lib/optimize.js b/build/lib/optimize.js index e4783e18569..2b59d926838 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -111,12 +111,17 @@ function toBundleStream(src, bundledFileHeader, bundles) { return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest); })); } +const DEFAULT_FILE_HEADER = [ + '/*!--------------------------------------------------------', + ' * Copyright (C) Microsoft Corporation. All rights reserved.', + ' *--------------------------------------------------------*/' +].join('\n'); function optimizeTask(opts) { const src = opts.src; const entryPoints = opts.entryPoints; const resources = opts.resources; const loaderConfig = opts.loaderConfig; - const bundledFileHeader = opts.header; + const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; return function () { diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index d15659ca6ea..6bf1233c303 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -154,7 +154,7 @@ export interface IOptimizeTaskOpts { /** * (basically the Copyright treatment) */ - header: string; + header?: string; /** * (emit bundleInfo.json file) */ @@ -169,12 +169,18 @@ export interface IOptimizeTaskOpts { languages?: Language[]; } +const DEFAULT_FILE_HEADER = [ + '/*!--------------------------------------------------------', + ' * Copyright (C) Microsoft Corporation. All rights reserved.', + ' *--------------------------------------------------------*/' +].join('\n'); + export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream { const src = opts.src; const entryPoints = opts.entryPoints; const resources = opts.resources; const loaderConfig = opts.loaderConfig; - const bundledFileHeader = opts.header; + const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; diff --git a/build/lib/test/i18n.test.js b/build/lib/test/i18n.test.js index 298104865ab..3dd104259fa 100644 --- a/build/lib/test/i18n.test.js +++ b/build/lib/test/i18n.test.js @@ -27,14 +27,14 @@ suite('XLF Parser Tests', () => { }); test('JSON file source path to Transifex resource match', () => { const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench'; - const platform = { name: 'vs/platform', project: editorProject }, editorContrib = { name: 'vs/editor/contrib', project: editorProject }, editor = { name: 'vs/editor', project: editorProject }, base = { name: 'vs/base', project: editorProject }, code = { name: 'vs/code', project: workbenchProject }, workbenchParts = { name: 'vs/workbench/contrib/html', project: workbenchProject }, workbenchServices = { name: 'vs/workbench/services/files', project: workbenchProject }, workbench = { name: 'vs/workbench', project: workbenchProject }; + const platform = { name: 'vs/platform', project: editorProject }, editorContrib = { name: 'vs/editor/contrib', project: editorProject }, editor = { name: 'vs/editor', project: editorProject }, base = { name: 'vs/base', project: editorProject }, code = { name: 'vs/code', project: workbenchProject }, workbenchParts = { name: 'vs/workbench/contrib/html', project: workbenchProject }, workbenchServices = { name: 'vs/workbench/services/textfile', project: workbenchProject }, workbench = { name: 'vs/workbench', project: workbenchProject }; assert.deepEqual(i18n.getResource('vs/platform/actions/browser/menusExtensionPoint'), platform); assert.deepEqual(i18n.getResource('vs/editor/contrib/clipboard/browser/clipboard'), editorContrib); assert.deepEqual(i18n.getResource('vs/editor/common/modes/modesRegistry'), editor); assert.deepEqual(i18n.getResource('vs/base/common/errorMessage'), base); assert.deepEqual(i18n.getResource('vs/code/electron-main/window'), code); assert.deepEqual(i18n.getResource('vs/workbench/contrib/html/browser/webview'), workbenchParts); - assert.deepEqual(i18n.getResource('vs/workbench/services/files/node/fileService'), workbenchServices); + assert.deepEqual(i18n.getResource('vs/workbench/services/textfile/node/testFileService'), workbenchServices); assert.deepEqual(i18n.getResource('vs/workbench/browser/parts/panel/panelActions'), workbench); }); }); diff --git a/build/lib/test/i18n.test.ts b/build/lib/test/i18n.test.ts index eebc7742457..29a0f665799 100644 --- a/build/lib/test/i18n.test.ts +++ b/build/lib/test/i18n.test.ts @@ -39,7 +39,7 @@ suite('XLF Parser Tests', () => { base = { name: 'vs/base', project: editorProject }, code = { name: 'vs/code', project: workbenchProject }, workbenchParts = { name: 'vs/workbench/contrib/html', project: workbenchProject }, - workbenchServices = { name: 'vs/workbench/services/files', project: workbenchProject }, + workbenchServices = { name: 'vs/workbench/services/textfile', project: workbenchProject }, workbench = { name: 'vs/workbench', project: workbenchProject}; assert.deepEqual(i18n.getResource('vs/platform/actions/browser/menusExtensionPoint'), platform); @@ -48,7 +48,7 @@ suite('XLF Parser Tests', () => { assert.deepEqual(i18n.getResource('vs/base/common/errorMessage'), base); assert.deepEqual(i18n.getResource('vs/code/electron-main/window'), code); assert.deepEqual(i18n.getResource('vs/workbench/contrib/html/browser/webview'), workbenchParts); - assert.deepEqual(i18n.getResource('vs/workbench/services/files/node/fileService'), workbenchServices); + assert.deepEqual(i18n.getResource('vs/workbench/services/textfile/node/testFileService'), workbenchServices); assert.deepEqual(i18n.getResource('vs/workbench/browser/parts/panel/panelActions'), workbench); }); }); \ No newline at end of file diff --git a/build/lib/typings/gulp-remote-src.d.ts b/build/lib/typings/gulp-remote-src.d.ts index 6ea57f84fe5..ff9026b79bb 100644 --- a/build/lib/typings/gulp-remote-src.d.ts +++ b/build/lib/typings/gulp-remote-src.d.ts @@ -1,4 +1,4 @@ -declare module 'gulp-remote-src' { +declare module 'gulp-remote-retry-src' { import stream = require("stream"); @@ -20,4 +20,4 @@ declare module 'gulp-remote-src' { } export = remote; -} \ No newline at end of file +} diff --git a/build/lib/watch/package.json b/build/lib/watch/package.json index 3afffdec7d3..b26f589ce0d 100644 --- a/build/lib/watch/package.json +++ b/build/lib/watch/package.json @@ -6,6 +6,6 @@ "private": true, "license": "MIT", "devDependencies": { - "gulp-watch": "^4.3.9" + "gulp-watch": "5.0.1" } } diff --git a/build/lib/watch/yarn.lock b/build/lib/watch/yarn.lock index 0f2ac1e204d..f7d5d976b1f 100644 --- a/build/lib/watch/yarn.lock +++ b/build/lib/watch/yarn.lock @@ -7,23 +7,29 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY= +ansi-colors@1.1.0, ansi-colors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" + ansi-wrap "^0.1.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + dependencies: + ansi-wrap "0.1.0" ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= +ansi-wrap@0.1.0, ansi-wrap@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= anymatch@^1.3.0: version "1.3.2" @@ -33,6 +39,14 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -53,97 +67,69 @@ arr-diff@^2.0.0: dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== -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-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -assert-plus@1.0.0, assert-plus@^1.0.0: +assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - integrity sha1-g+9cqGCysy5KDe7e6MdxudtXRx4= +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - integrity sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40= +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: - tweetnacl "^0.14.3" - -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" binary-extensions@^1.0.0: version "1.10.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" integrity sha1-muuabF6IY4qtFx4Wf1kAq+JINdA= -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= - dependencies: - hoek "2.x.x" - brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -161,64 +147,127 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.0.0, chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" -chokidar@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +chokidar@^2.0.0: + version "2.1.6" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" + integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" is-binary-path "^1.0.0" - is-glob "^2.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" path-is-absolute "^1.0.0" - readdirp "^2.0.0" + readdirp "^2.2.1" + upath "^1.1.1" optionalDependencies: - fsevents "^1.0.0" + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" + integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= clone-stats@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + clone@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" integrity sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8= -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cloneable-readable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" 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" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - integrity sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk= +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: - delayed-stream "~1.0.0" + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== concat-map@0.0.1: version "0.0.1" @@ -230,46 +279,61 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -core-util-is@1.0.2, core-util-is@~1.0.0: +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= - dependencies: - boom "2.x.x" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -dateformat@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" - integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= - -debug@^2.2.0: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8= +debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" -delayed-stream@~1.0.0: +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" delegates@^1.0.0: version "1.0.0" @@ -281,25 +345,6 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1" integrity sha1-ca1dIEvxempsqPRQxhRUBm70YeE= -duplexer2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= - dependencies: - readable-stream "~1.1.9" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - integrity sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU= - dependencies: - jsbn "~0.1.0" - -escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -307,6 +352,19 @@ expand-brackets@^0.1.4: dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" @@ -314,10 +372,20 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" extglob@^0.3.1: version "0.3.2" @@ -326,17 +394,27 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extsprintf@1.3.0, extsprintf@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -fancy-log@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948" - integrity sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg= +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: - chalk "^1.1.1" + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fancy-log@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" + integrity sha1-9BEl49hPLn2JpD0G2VjI94vha+E= + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" time-stamp "^1.0.0" filename-regex@^2.0.0: @@ -355,6 +433,16 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + first-chunk-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" @@ -362,7 +450,7 @@ first-chunk-stream@^2.0.0: dependencies: readable-stream "^2.0.2" -for-in@^1.0.1: +for-in@^1.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" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= @@ -374,51 +462,32 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - integrity sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE= +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" + map-cache "^0.2.2" + +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + dependencies: + minipass "^2.2.1" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - integrity sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q== +fsevents@^1.2.7: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU= - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" + nan "^2.12.1" + node-pre-gyp "^0.12.0" gauge@~2.7.3: version "2.7.4" @@ -434,12 +503,10 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= glob-base@^0.3.0: version "0.3.0" @@ -456,7 +523,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob-parent@^3.0.1: +glob-parent@^3.0.1, glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= @@ -476,120 +543,83 @@ glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -glogg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" - integrity sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U= - dependencies: - sparkles "^1.0.0" +graceful-fs@^4.1.11: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -gulp-util@^3.0.7: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - -gulp-watch@^4.3.9: - version "4.3.11" - resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-4.3.11.tgz#162fc563de9fc770e91f9a7ce3955513a9a118c0" - integrity sha1-Fi/FY96fx3DpH5p845VVE6mhGMA= +gulp-watch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-5.0.1.tgz#83d378752f5bfb46da023e73c17ed1da7066215d" + integrity sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog== dependencies: + ansi-colors "1.1.0" anymatch "^1.3.0" - chokidar "^1.6.1" + chokidar "^2.0.0" + fancy-log "1.3.2" glob-parent "^3.0.1" - gulp-util "^3.0.7" object-assign "^4.1.0" path-is-absolute "^1.0.1" + plugin-error "1.0.1" readable-stream "^2.2.2" slash "^1.0.0" - vinyl "^1.2.0" + vinyl "^2.1.0" vinyl-file "^2.0.0" -gulplog@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" - integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U= - dependencies: - glogg "^1.0.0" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - integrity sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4= - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - integrity sha1-M0gdDxu/9gDdID11gSpqX7oALio= - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= - dependencies: - sparkles "^1.0.0" - has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" inflight@^1.0.4: version "1.0.6" @@ -599,16 +629,35 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" integrity sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4= +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" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -621,6 +670,38 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -633,17 +714,24 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= -is-extglob@^2.1.0: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= @@ -669,6 +757,13 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0: + 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-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -683,6 +778,13 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -693,20 +795,15 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - 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= -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +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== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" @@ -720,49 +817,12 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -kind-of@^3.0.2: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= @@ -776,104 +836,27 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= - -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= - -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: - lodash._root "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= - -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" + object-visit "^1.0.0" micromatch@^2.1.5: version "2.3.11" @@ -894,19 +877,26 @@ micromatch@^2.1.5: parse-glob "^3.0.4" regex-cache "^0.4.2" -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE= - -mime-types@^2.1.12, mime-types@~2.1.7: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo= +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: - mime-db "~1.30.0" + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -918,12 +908,35 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.2.0: +minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -"mkdirp@>=0.5 0", mkdirp@^0.5.1: +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -935,34 +948,57 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: - duplexer2 "0.0.2" + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" -nan@^2.3.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" - integrity sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY= +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - integrity sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ== +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== dependencies: detect-libc "^1.0.2" - hawk "3.1.3" mkdirp "^0.5.1" + needle "^2.2.1" nopt "^4.0.1" + npm-packlist "^1.1.6" npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" + rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" + tar "^4" nopt@^4.0.1: version "4.0.1" @@ -972,13 +1008,31 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-path@^2.0.0, normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -994,21 +1048,27 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= - object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -1017,7 +1077,14 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.3: +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -1052,6 +1119,11 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -1062,11 +1134,6 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU= - pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -1084,26 +1151,36 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +plugin-error@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" + integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== + dependencies: + ansi-colors "^1.0.1" + arr-diff "^4.0.0" + arr-union "^3.1.0" + extend-shallow "^3.0.2" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM= - randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -1112,17 +1189,17 @@ randomatic@^1.1.3: is-number "^3.0.0" kind-of "^4.0.0" -rc@^1.1.7: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" - integrity sha1-2M6ctX6NZNnHut2YdsfDTL48cHc= +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: - deep-extend "~0.4.0" + deep-extend "^0.6.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ== @@ -1135,25 +1212,27 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= +readable-stream@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg= +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" + graceful-fs "^4.1.11" + micromatch "^3.1.10" readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" regex-cache@^0.4.2: version "0.4.4" @@ -1162,6 +1241,14 @@ regex-cache@^0.4.2: dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -1172,7 +1259,7 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= -repeat-string@^1.5.2: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -1182,46 +1269,55 @@ replace-ext@0.0.1: resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA= - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: glob "^7.0.5" -safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -1232,10 +1328,15 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" signal-exit@^3.0.0: version "3.0.2" @@ -1247,32 +1348,71 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: - hoek "2.x.x" + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" -sparkles@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" - integrity sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM= - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - integrity sha1-US322mKHFEMW3EwY/hzx2UBzm+M= +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" @@ -1283,11 +1423,6 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -1295,10 +1430,12 @@ string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg= +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" @@ -1327,90 +1464,87 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - integrity sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg== +tar@^4: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= -tough-cookie@~2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - integrity sha1-C2GKVWW23qkL80JdBNVe3EdadWE= +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: - punycode "^1.4.1" + kind-of "^3.0.2" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: - safe-buffer "^5.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +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" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - vinyl-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a" @@ -1423,16 +1557,7 @@ vinyl-file@^2.0.0: strip-bom-stream "^2.0.0" vinyl "^1.1.0" -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^1.1.0, vinyl@^1.2.0: +vinyl@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ= @@ -1441,6 +1566,18 @@ vinyl@^1.1.0, vinyl@^1.2.0: clone-stats "^0.0.1" replace-ext "0.0.1" +vinyl@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86" + integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -1453,7 +1590,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= +yallist@^3.0.0, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index ed3a8f5d260..afba093b25c 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -5,6 +5,8 @@ declare namespace monaco { + // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY. + export type Thenable = PromiseLike; export interface IDisposable { diff --git a/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe index 13290a7abb5..f1a74a25e30 100644 --- a/build/monaco/monaco.usage.recipe +++ b/build/monaco/monaco.usage.recipe @@ -30,7 +30,7 @@ import * as editorAPI from './vs/editor/editor.api'; a = (>b).type; a = (b).start; a = (b).end; - a = (>b).getProxyObject; // IWorkerClient + a = (>b).getProxyObject; // IWorkerClient a = create1; a = create2; a = (b).extensionId; diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 80a4f0eeb5c..cd41092192c 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -35,6 +35,8 @@ yarnInstall('extensions'); // node modules shared by all extensions yarnInstall('remote'); // node modules used by vscode server +yarnInstall('remote/web'); // node modules used by vscode web + const allExtensionFolders = fs.readdirSync('extensions'); const extensions = allExtensionFolders.filter(e => { try { diff --git a/build/package.json b/build/package.json index 622b7b59351..2a1c775c736 100644 --- a/build/package.json +++ b/build/package.json @@ -20,7 +20,7 @@ "@types/minimatch": "^3.0.3", "@types/minimist": "^1.2.0", "@types/mocha": "2.2.39", - "@types/node": "8.0.33", + "@types/node": "^10.14.8", "@types/pump": "^1.0.1", "@types/request": "^2.47.0", "@types/rimraf": "^2.0.2", @@ -29,7 +29,7 @@ "@types/uglify-es": "^3.0.0", "@types/underscore": "^1.8.9", "@types/xml2js": "0.0.33", - "applicationinsights": "1.0.6", + "applicationinsights": "1.0.8", "azure-storage": "^2.1.0", "documentdb": "1.13.0", "github-releases": "^0.4.1", @@ -42,6 +42,7 @@ "tslint": "^5.9.1", "typescript": "3.5.2", "vsce": "1.48.0", + "vscode-telemetry-extractor": "^1.5.1", "xml2js": "^0.4.17" }, "scripts": { @@ -50,4 +51,4 @@ "postinstall": "npm run compile", "npmCheckJs": "tsc --noEmit" } -} \ No newline at end of file +} diff --git a/build/yarn.lock b/build/yarn.lock index 3bba51751e1..7d00ac18872 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" @@ -166,10 +195,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.14.8": + version "10.14.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.13.tgz#ac786d623860adf39a3f51d629480aacd6a6eec7" + integrity sha512-yN/FNNW1UYsRR1wwAoyOwqvDuLDtVXnaJTZ898XIw/Q5cCaeVAlVwvsmXLX5PuiScBYwZsZU4JYSHB3TvfdwvQ== "@types/pump@^1.0.1": version "1.0.1" @@ -328,10 +357,10 @@ ansi-wrap@0.1.0: resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= -applicationinsights@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.6.tgz#bc201810de91cea910dab34e8ad35ecde488edeb" - integrity sha512-VQT3kBpJVPw5fCO5n+WUeSx0VHjxFtD7znYbILBlVgOS9/cMDuGFmV2Br3ObzFyZUDGNbEfW36fD1y2/vAiCKw== +applicationinsights@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" + integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg== dependencies: diagnostic-channel "0.2.0" diagnostic-channel-publishers "0.2.1" @@ -344,16 +373,36 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +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@^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.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= +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" @@ -481,6 +530,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.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" @@ -548,6 +604,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== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -584,6 +645,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" @@ -710,6 +781,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" @@ -829,11 +907,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" @@ -841,6 +938,20 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.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" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -864,6 +975,15 @@ form-data@~2.3.1: combined-stream "1.0.6" mime-types "^2.1.12" +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.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -886,6 +1006,13 @@ github-releases@^0.4.1: prettyjson "1.2.1" request "2.81.0" +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.6, glob@^7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -898,6 +1025,32 @@ glob@^7.0.6, glob@^7.1.1: 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" + glogg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810" @@ -910,6 +1063,11 @@ graceful-fs@4.X: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= +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== + gulp-bom@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gulp-bom/-/gulp-bom-1.0.0.tgz#38a183a07187bd57a7922d37977441f379df2abf" @@ -1086,6 +1244,11 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" +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" @@ -1094,21 +1257,75 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +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-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +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-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@^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-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-typedarray@~1.0.0: version "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.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -1171,6 +1388,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" @@ -1248,6 +1472,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" @@ -1331,6 +1560,19 @@ 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@^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" @@ -1382,6 +1624,17 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +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" @@ -1480,6 +1733,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" @@ -1495,6 +1753,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== + prettyjson@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" @@ -1667,6 +1930,16 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.5" +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== + +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" @@ -1702,6 +1975,11 @@ semver@^5.1.0, semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" @@ -1825,6 +2103,13 @@ tmp@0.0.29: dependencies: os-tmpdir "~1.0.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" + tough-cookie@~2.3.0: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" @@ -1839,6 +2124,20 @@ tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +ts-morph@^3.1.3: + 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" @@ -1899,11 +2198,26 @@ 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" integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== +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" @@ -1914,6 +2228,11 @@ underscore@^1.8.3: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== +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== + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -1994,6 +2313,20 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" +vscode-ripgrep@^1.5.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" + integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== + +vscode-telemetry-extractor@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.5.1.tgz#67249e4ca9c65a21800ca53880732f8cef98d0fa" + integrity sha512-B5SnEdRiDrI4o6NMG9iHmengoaW1rxUQmS/sCaripgnchm+P79JURmKxhfXr5eRo4Mr1QSenFT/SDNaEop7aoQ== + dependencies: + command-line-args "^5.1.1" + ts-morph "^3.1.3" + vscode-ripgrep "^1.5.5" + 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/cgmanifest.json b/cgmanifest.json index b8c4f3bfefc..638303702ae 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "5d67ec3da5376a5058990e8a9557bc9124ad59a8" + "commitHash": "36ea114ac0616e469e75ae94e6d53af48925e036" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "4.2.5" + "version": "4.2.7" }, { "component": { diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts index 913c5288809..aff533d86d9 100644 --- a/extensions/configuration-editing/src/extension.ts +++ b/extensions/configuration-editing/src/extension.ts @@ -63,11 +63,20 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { const indexOf$ = document.lineAt(position.line).text.indexOf('$'); const startPosition = indexOf$ >= 0 ? new vscode.Position(position.line, indexOf$) : position; - return [{ label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") }, { label: 'workspaceFolderBasename', detail: localize('workspaceFolderBasename', "The name of the folder opened in VS Code without any slashes (/)") }, - { label: 'relativeFile', detail: localize('relativeFile', "The current opened file relative to ${workspaceFolder}") }, { label: 'file', detail: localize('file', "The current opened file") }, { label: 'cwd', detail: localize('cwd', "The task runner's current working directory on startup") }, - { label: 'lineNumber', detail: localize('lineNumber', "The current selected line number in the active file") }, { label: 'selectedText', detail: localize('selectedText', "The current selected text in the active file") }, - { label: 'fileDirname', detail: localize('fileDirname', "The current opened file's dirname") }, { label: 'fileExtname', detail: localize('fileExtname', "The current opened file's extension") }, { label: 'fileBasename', detail: localize('fileBasename', "The current opened file's basename") }, - { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") }].map(variable => ({ + return [ + { label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") }, + { label: 'workspaceFolderBasename', detail: localize('workspaceFolderBasename', "The name of the folder opened in VS Code without any slashes (/)") }, + { label: 'relativeFile', detail: localize('relativeFile', "The current opened file relative to ${workspaceFolder}") }, + { label: 'relativeFileDirname', detail: localize('relativeFileDirname', "The current opened file's dirname relative to ${workspaceFolder}") }, + { label: 'file', detail: localize('file', "The current opened file") }, + { label: 'cwd', detail: localize('cwd', "The task runner's current working directory on startup") }, + { label: 'lineNumber', detail: localize('lineNumber', "The current selected line number in the active file") }, + { label: 'selectedText', detail: localize('selectedText', "The current selected text in the active file") }, + { label: 'fileDirname', detail: localize('fileDirname', "The current opened file's dirname") }, + { label: 'fileExtname', detail: localize('fileExtname', "The current opened file's extension") }, + { label: 'fileBasename', detail: localize('fileBasename', "The current opened file's basename") }, + { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") } + ].map(variable => ({ label: '${' + variable.label + '}', range: new vscode.Range(startPosition, position), detail: variable.detail diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index fcf971bc11f..d430c4d1518 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -13,8 +13,7 @@ { "open": "{", "close": "}" }, { "open": "(", "close": ")" }, { "open": "'", "close": "'", "notIn": ["string", "comment"] }, - { "open": "\"", "close": "\"", "notIn": ["string"] }, - { "open": "/**", "close": " */", "notIn": ["string", "comment"] } + { "open": "\"", "close": "\"", "notIn": ["string"] } ], "surroundingPairs": [ ["{", "}"], @@ -30,4 +29,4 @@ "end": "^\\s*#pragma\\s+endregion\\b" } } -} \ No newline at end of file +} diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index 8d8542f5a1e..ee8c9973d3a 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString, workspace, TextDocument, SelectionRange } from 'vscode'; +import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString, workspace } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Disposable } from 'vscode-languageclient'; import { getCustomDataPathsInAllWorkspaces, getCustomDataPathsFromAllExtensions } from './customData'; @@ -78,26 +78,6 @@ export function activate(context: ExtensionContext) { client.onReady().then(() => { context.subscriptions.push(initCompletionProvider()); - - documentSelector.forEach(selector => { - context.subscriptions.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 []; - } - })); - }); }); function initCompletionProvider(): Disposable { diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index 6f2e734a109..c6e8600d2ae 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -9,7 +9,7 @@ }, "main": "./out/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.2", + "vscode-css-languageservice": "^4.0.3-next.1", "vscode-languageserver": "^5.3.0-next.8" }, "devDependencies": { diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index cf539df1e1d..0bfd886c310 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -8,11 +8,12 @@ import { } from 'vscode-languageserver'; import URI from 'vscode-uri'; import { TextDocument, CompletionList, Position } from 'vscode-languageserver-types'; +import { stat as fsStat } from 'fs'; -import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice'; +import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, FileSystemProvider, FileType } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; import { getPathCompletionParticipant } from './pathCompletion'; -import { formatError, runSafe } from './utils/runner'; +import { formatError, runSafe, runSafeAsync } from './utils/runner'; import { getDocumentContext } from './utils/documentContext'; import { getDataProviders } from './customData'; @@ -52,6 +53,45 @@ let workspaceFolders: WorkspaceFolder[]; const languageServices: { [id: string]: LanguageService } = {}; +const fileSystemProvider: FileSystemProvider = { + stat(documentUri: string) { + const filePath = URI.parse(documentUri).fsPath; + + return new Promise((c, e) => { + fsStat(filePath, (err, stats) => { + if (err) { + if (err.code === 'ENOENT') { + return c({ + type: FileType.Unknown, + ctime: -1, + mtime: -1, + size: -1 + }); + } else { + return e(err); + } + } + + let type = FileType.Unknown; + if (stats.isFile()) { + type = FileType.File; + } else if (stats.isDirectory) { + type = FileType.Directory; + } else if (stats.isSymbolicLink) { + type = FileType.SymbolicLink; + } + + c({ + type, + ctime: stats.ctime.getTime(), + mtime: stats.mtime.getTime(), + size: stats.size + }); + }); + }); + } +}; + // After the server has started the client sends an initialize request. The server receives // in the passed params the rootPath of the workspace plus the client capabilities. connection.onInitialize((params: InitializeParams): InitializeResult => { @@ -81,9 +121,9 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { scopedSettingsSupport = !!getClientCapability('workspace.configuration', false); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); - languageServices.css = getCSSLanguageService({ customDataProviders }); - languageServices.scss = getSCSSLanguageService({ customDataProviders }); - languageServices.less = getLESSLanguageService({ customDataProviders }); + languageServices.css = getCSSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); + languageServices.scss = getSCSSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); + languageServices.less = getLESSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); const capabilities: ServerCapabilities = { // Tell the client that the server works in FULL text document sync mode @@ -100,7 +140,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { codeActionProvider: true, renameProvider: true, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; }); @@ -256,13 +297,13 @@ connection.onDocumentHighlight((documentHighlightParams, token) => { }); -connection.onDocumentLinks((documentLinkParams, token) => { - return runSafe(() => { +connection.onDocumentLinks(async (documentLinkParams, token) => { + return runSafeAsync(async () => { const document = documents.get(documentLinkParams.textDocument.uri); if (document) { const documentContext = getDocumentContext(document.uri, workspaceFolders); const stylesheet = stylesheets.get(document); - return getLanguageService(document).findDocumentLinks(document, stylesheet, documentContext); + return await getLanguageService(document).findDocumentLinks2(document, stylesheet, documentContext); } return []; }, [], `Error while computing document links for ${documentLinkParams.textDocument.uri}`, token); @@ -334,7 +375,7 @@ 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); const positions: Position[] = params.positions; @@ -343,8 +384,8 @@ connection.onRequest('$/textDocument/selectionRanges', async (params, token) => const stylesheet = stylesheets.get(document); return getLanguageService(document).getSelectionRanges(document, positions, stylesheet); } - return Promise.resolve(null); - }, null, `Error while computing selection ranges for ${params.textDocument.uri}`, token); + return []; + }, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token); }); diff --git a/extensions/css-language-features/server/src/pathCompletion.ts b/extensions/css-language-features/server/src/pathCompletion.ts index 4d988a52da9..aafed82b513 100644 --- a/extensions/css-language-features/server/src/pathCompletion.ts +++ b/extensions/css-language-features/server/src/pathCompletion.ts @@ -154,10 +154,10 @@ function pathToReplaceRange(valueBeforeCursor: string, fullValue: string, fullVa const valueAfterLastSlash = fullValue.slice(lastIndexOfSlash + 1); const startPos = shiftPosition(fullValueRange.end, -valueAfterLastSlash.length); // If whitespace exists, replace until it - const whiteSpaceIndex = valueAfterLastSlash.indexOf(' '); + const whitespaceIndex = valueAfterLastSlash.indexOf(' '); let endPos; - if (whiteSpaceIndex !== -1) { - endPos = shiftPosition(startPos, whiteSpaceIndex); + if (whitespaceIndex !== -1) { + endPos = shiftPosition(startPos, whitespaceIndex); } else { endPos = fullValueRange.end; } diff --git a/extensions/css-language-features/server/src/utils/runner.ts b/extensions/css-language-features/server/src/utils/runner.ts index df024167dab..98a7a96f9aa 100644 --- a/extensions/css-language-features/server/src/utils/runner.ts +++ b/extensions/css-language-features/server/src/utils/runner.ts @@ -17,6 +17,27 @@ export function formatError(message: string, err: any): string { return message; } +export function runSafeAsync(func: () => Thenable, errorVal: T, errorMessage: string, token: CancellationToken): Thenable> { + return new Promise>((resolve) => { + setImmediate(() => { + if (token.isCancellationRequested) { + resolve(cancelValue()); + } + return func().then(result => { + if (token.isCancellationRequested) { + resolve(cancelValue()); + return; + } else { + resolve(result); + } + }, e => { + console.error(formatError(errorMessage, e)); + resolve(errorVal); + }); + }); + }); +} + export function runSafe(func: () => T, errorVal: T, errorMessage: string, token: CancellationToken): Thenable> { return new Promise>((resolve) => { setImmediate(() => { diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index c5bfa63c869..d93eec392c7 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -781,13 +781,14 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.2.tgz#7496e538b0c151feac16d5888cc0b1b104f4c736" - integrity sha512-pTnfXbsME3pl+yDfhUp/mtvPyIJk0Le4zqJxDn56s9GY9LqY0RmkSEh0oHH6D0HXR3Ni6wKosIaqu8a2G0+jdw== +vscode-css-languageservice@^4.0.3-next.1: + version "4.0.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.1.tgz#e89d01ce0d79b3e6c2642f5e3ad73cb8160d38d9" + integrity sha512-Zrm5TeraVUJ8vRikWhFt259dQu+WK+Ie3K5UA8BB4kqcanoM+1mcnIt8fPkTXlZLbiEWElrkJ9yuYbDNkufeBg== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" + vscode-uri "^2.0.3" vscode-jsonrpc@^4.1.0-next.2: version "4.1.0-next.2" @@ -831,6 +832,11 @@ vscode-uri@^1.0.6: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" diff --git a/extensions/css/.vscodeignore b/extensions/css/.vscodeignore index 0a622e7e300..52ebcbd68b2 100644 --- a/extensions/css/.vscodeignore +++ b/extensions/css/.vscodeignore @@ -1,2 +1,3 @@ test/** cgmanifest.json +.vscode \ No newline at end of file diff --git a/extensions/debug-server-ready/.vscodeignore b/extensions/debug-server-ready/.vscodeignore index 36e8b0714fa..609d4c28b22 100644 --- a/extensions/debug-server-ready/.vscodeignore +++ b/extensions/debug-server-ready/.vscodeignore @@ -2,4 +2,5 @@ src/** tsconfig.json out/** extension.webpack.config.js -yarn.lock \ No newline at end of file +yarn.lock +.vscode \ No newline at end of file diff --git a/extensions/debug-server-ready/src/extension.ts b/extensions/debug-server-ready/src/extension.ts index d6e122f9624..64c4ccffea6 100644 --- a/extensions/debug-server-ready/src/extension.ts +++ b/extensions/debug-server-ready/src/extension.ts @@ -137,8 +137,7 @@ class ServerReadyDetector extends vscode.Disposable { break; case 'debugWithChrome': - const chrome = vscode.extensions.getExtension('msjsdiag.debugger-for-chrome'); - if (chrome) { + if (vscode.env.remoteName === 'wsl' || !!vscode.extensions.getExtension('msjsdiag.debugger-for-chrome')) { vscode.debug.startDebugging(session.workspaceFolder, { type: 'chrome', name: 'Chrome Debug', diff --git a/extensions/emmet/.vscodeignore b/extensions/emmet/.vscodeignore index 50d0ee883e6..573d91ebe6b 100644 --- a/extensions/emmet/.vscodeignore +++ b/extensions/emmet/.vscodeignore @@ -6,3 +6,4 @@ extension.webpack.config.js CONTRIBUTING.md cgmanifest.json yarn.lock +.vscode \ No newline at end of file diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index e548023487f..26510e803cb 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -84,8 +84,8 @@ function doWrapping(individualLines: boolean, args: any) { const firstLineOfSelection = editor.document.lineAt(rangeToReplace.start).text.substr(rangeToReplace.start.character); const matches = firstLineOfSelection.match(/^(\s*)/); - const extraWhiteSpaceSelected = matches ? matches[1].length : 0; - rangeToReplace = new vscode.Range(rangeToReplace.start.line, rangeToReplace.start.character + extraWhiteSpaceSelected, rangeToReplace.end.line, rangeToReplace.end.character); + const extraWhitespaceSelected = matches ? matches[1].length : 0; + rangeToReplace = new vscode.Range(rangeToReplace.start.line, rangeToReplace.start.character + extraWhitespaceSelected, rangeToReplace.end.line, rangeToReplace.end.character); let textToWrapInPreview: string[]; let textToReplace = editor.document.getText(rangeToReplace); @@ -94,8 +94,8 @@ function doWrapping(individualLines: boolean, args: any) { } else { const wholeFirstLine = editor.document.lineAt(rangeToReplace.start).text; const otherMatches = wholeFirstLine.match(/^(\s*)/); - const preceedingWhiteSpace = otherMatches ? otherMatches[1] : ''; - textToWrapInPreview = rangeToReplace.isSingleLine ? [textToReplace] : ['\n\t' + textToReplace.split('\n' + preceedingWhiteSpace).join('\n\t') + '\n']; + const preceedingWhitespace = otherMatches ? otherMatches[1] : ''; + textToWrapInPreview = rangeToReplace.isSingleLine ? [textToReplace] : ['\n\t' + textToReplace.split('\n' + preceedingWhitespace).join('\n\t') + '\n']; } textToWrapInPreview = textToWrapInPreview.map(e => e.replace(/(\$\d)/g, '\\$1')); diff --git a/extensions/git/package.json b/extensions/git/package.json index 814f53020aa..4a789aaa6ad 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/git/src/api/api1.ts b/extensions/git/src/api/api1.ts index 25742babc15..a4fd677db27 100644 --- a/extensions/git/src/api/api1.ts +++ b/extensions/git/src/api/api1.ts @@ -5,7 +5,7 @@ import { Model } from '../model'; import { Repository as BaseRepository, Resource } from '../repository'; -import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions } from './git'; +import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState } from './git'; import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode'; import { mapEvent } from '../util'; @@ -214,6 +214,14 @@ export class ApiImpl implements API { readonly git = new ApiGit(this._model); + get state(): APIState { + return this._model.state; + } + + get onDidChangeState(): Event { + return this._model.onDidChangeState; + } + get onDidOpenRepository(): Event { return mapEvent(this._model.onDidOpenRepository, r => new ApiRepository(r)); } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index 9444ea1fada..21195974fc1 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -176,7 +176,11 @@ export interface Repository { log(options?: LogOptions): Promise; } +export type APIState = 'uninitialized' | 'initialized'; + export interface API { + readonly state: APIState; + readonly onDidChangeState: Event; readonly git: Git; readonly repositories: Repository[]; readonly onDidOpenRepository: Event; diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index a9b53103702..d75e6f9bc45 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1115,7 +1115,7 @@ export class CommandCenter { if (scmResources.length === 1) { if (untrackedCount > 0) { - message = localize('confirm delete', "Are you sure you want to DELETE {0}?", path.basename(scmResources[0].resourceUri.fsPath)); + message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(scmResources[0].resourceUri.fsPath)); yes = localize('delete file', "Delete file"); } else { if (scmResources[0].type === Status.DELETED) { @@ -1134,7 +1134,7 @@ export class CommandCenter { } if (untrackedCount > 0) { - message = `${message}\n\n${localize('warn untracked', "This will DELETE {0} untracked files!", untrackedCount)}`; + message = `${message}\n\n${localize('warn untracked', "This will DELETE {0} untracked files!\nThis is IRREVERSIBLE!\nThese files will be FOREVER LOST.", untrackedCount)}`; } } @@ -1175,7 +1175,7 @@ export class CommandCenter { await repository.clean(resources.map(r => r.resourceUri)); return; } else if (resources.length === 1) { - const message = localize('confirm delete', "Are you sure you want to DELETE {0}?", path.basename(resources[0].resourceUri.fsPath)); + const message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(resources[0].resourceUri.fsPath)); const yes = localize('delete file', "Delete file"); const pick = await window.showWarningMessage(message, { modal: true }, yes); diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index a04dc33c8be..da6a940428e 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -12,7 +12,7 @@ import * as path from 'path'; import * as fs from 'fs'; import * as nls from 'vscode-nls'; import { fromGitUri } from './uri'; -import { GitErrorCodes } from './api/git'; +import { GitErrorCodes, APIState as State } from './api/git'; const localize = nls.loadMessageBundle(); @@ -63,15 +63,22 @@ export class Model { private possibleGitRepositoryPaths = new Set(); + private _onDidChangeState = new EventEmitter(); + readonly onDidChangeState = this._onDidChangeState.event; + + private _state: State = 'uninitialized'; + get state(): State { return this._state; } + + setState(state: State): void { + this._state = state; + this._onDidChangeState.fire(state); + } + private disposables: Disposable[] = []; constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) { workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); - this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }); - window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); - this.onDidChangeVisibleTextEditors(window.visibleTextEditors); - workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); const fsWatcher = workspace.createFileSystemWatcher('**'); @@ -82,7 +89,15 @@ export class Model { const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri)); onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables); - this.scanWorkspaceFolders(); + this.doInitialScan().finally(() => this.setState('initialized')); + } + + private async doInitialScan(): Promise { + await Promise.all([ + this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }), + this.onDidChangeVisibleTextEditors(window.visibleTextEditors), + this.scanWorkspaceFolders() + ]); } /** @@ -157,8 +172,8 @@ export class Model { .filter(r => !activeRepositories.has(r!.repository)) .filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; - possibleRepositoryFolders.forEach(p => this.openRepository(p.uri.fsPath)); openRepositoriesToDispose.forEach(r => r.dispose()); + await Promise.all(possibleRepositoryFolders.map(p => this.openRepository(p.uri.fsPath))); } private onDidChangeConfiguration(): void { @@ -175,7 +190,7 @@ export class Model { openRepositoriesToDispose.forEach(r => r.dispose()); } - private onDidChangeVisibleTextEditors(editors: TextEditor[]): void { + private async onDidChangeVisibleTextEditors(editors: TextEditor[]): Promise { const config = workspace.getConfiguration('git'); const autoRepositoryDetection = config.get('autoRepositoryDetection'); @@ -183,7 +198,7 @@ export class Model { return; } - editors.forEach(editor => { + await Promise.all(editors.map(async editor => { const uri = editor.document.uri; if (uri.scheme !== 'file') { @@ -196,8 +211,8 @@ export class Model { return; } - this.openRepository(path.dirname(uri.fsPath)); - }); + await this.openRepository(path.dirname(uri.fsPath)); + })); } @sequentialize @@ -236,6 +251,7 @@ export class Model { const repository = new Repository(this.git.open(repositoryRoot, dotGit), this.globalState, this.outputChannel); this.open(repository); + await repository.status(); } catch (err) { if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) { return; @@ -421,4 +437,4 @@ export class Model { this.possibleGitRepositoryPaths.clear(); this.disposables = dispose(this.disposables); } -} \ No newline at end of file +} diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index a581f9f5fd4..196a1bddade 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -519,8 +519,8 @@ class DotGitWatcher implements IFileWatcher { this.transientDisposables.push(upstreamWatcher); upstreamWatcher.event(this.emitter.fire, this.emitter, this.transientDisposables); } catch (err) { - if (env.logLevel <= LogLevel.Info) { - this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}'. Ref is most likely packed.`); + if (env.logLevel <= LogLevel.Error) { + this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}', is most likely packed.\n${err.stack || err}`); } } } @@ -651,19 +651,30 @@ export class Repository implements Disposable { const onWorkspaceRepositoryFileChange = filterEvent(onWorkspaceFileChange, uri => isDescendant(repository.root, uri.fsPath)); const onWorkspaceWorkingTreeFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => !/\/\.git($|\/)/.test(uri.path)); - const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); - this.disposables.push(dotGitFileWatcher); + let onDotGitFileChange: Event; + + try { + const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); + onDotGitFileChange = dotGitFileWatcher.event; + this.disposables.push(dotGitFileWatcher); + } catch (err) { + if (env.logLevel <= LogLevel.Error) { + outputChannel.appendLine(`Failed to watch '${this.dotGit}', reverting to legacy API file watched. Some events might be lost.\n${err.stack || err}`); + } + + onDotGitFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => /\/\.git($|\/)/.test(uri.path)); + } // FS changes should trigger `git status`: // - any change inside the repository working tree // - any change whithin the first level of the `.git` folder, except the folder itself and `index.lock` - const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, dotGitFileWatcher.event); + const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, onDotGitFileChange); onFileChange(this.onFileChange, this, this.disposables); // Relevate repository changes should trigger virtual document change events - dotGitFileWatcher.event(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); + onDotGitFileChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); - this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, dotGitFileWatcher.event, outputChannel)); + this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, onDotGitFileChange, outputChannel)); const root = Uri.file(repository.root); this._sourceControl = scm.createSourceControl('git', 'Git', root); @@ -713,7 +724,6 @@ export class Repository implements Disposable { this.disposables.push(progressManager); this.updateCommitTemplate(); - this.status(); } validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined { diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 6fe90190729..5f98f732b52 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, SelectionRange } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; @@ -87,26 +87,6 @@ export function activate(context: ExtensionContext) { } }); toDispose.push(disposable); - - documentSelector.forEach(selector => { - context.subscriptions.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 []; - } - })); - }); }); languages.setLanguageConfiguration('html', { diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index e97a42ab0a6..95a97f1110f 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,12 +9,12 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.2", - "vscode-html-languageservice": "^3.0.0", + "vscode-css-languageservice": "^4.0.3-next.1", + "vscode-html-languageservice": "^3.0.4-next.0", "vscode-languageserver": "^5.3.0-next.8", "vscode-languageserver-types": "3.15.0-next.2", "vscode-nls": "^4.1.1", - "vscode-uri": "^2.0.1" + "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index e3e62991aca..01b43d9a9ba 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -96,7 +96,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { get folders() { return workspaceFolders; } }; - languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace, providers); + languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace, params.capabilities, providers); documents.onDidClose(e => { languageModes.onDocumentRemoved(e.document); @@ -135,7 +135,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { signatureHelpProvider: { triggerCharacters: ['('] }, referencesProvider: true, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; }); @@ -454,7 +455,7 @@ connection.onFoldingRanges((params, token) => { }, null, `Error while computing folding regions 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); const positions: Position[] = params.positions; @@ -465,8 +466,8 @@ connection.onRequest('$/textDocument/selectionRanges', async (params, token) => return htmlMode.getSelectionRanges(document, positions); } } - return Promise.resolve(null); - }, null, `Error while computing selection ranges for ${params.textDocument.uri}`, token); + return []; + }, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token); }); diff --git a/extensions/html-language-features/server/src/modes/cssMode.ts b/extensions/html-language-features/server/src/modes/cssMode.ts index 168c7ceffa0..6e60c32d87c 100644 --- a/extensions/html-language-features/server/src/modes/cssMode.ts +++ b/extensions/html-language-features/server/src/modes/cssMode.ts @@ -5,13 +5,12 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { TextDocument, Position, Range, CompletionList } from 'vscode-languageserver-types'; -import { getCSSLanguageService, Stylesheet, FoldingRange } from 'vscode-css-languageservice'; +import { Stylesheet, FoldingRange, LanguageService as CSSLanguageService } from 'vscode-css-languageservice'; import { LanguageMode, Workspace } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; import { Color } from 'vscode-languageserver'; -export function getCSSMode(documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { - let cssLanguageService = getCSSLanguageService(); +export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { let embeddedCSSDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument('css')); let cssStylesheets = getLanguageModelCache(10, 60, document => cssLanguageService.parseStylesheet(document)); diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index b44b2442420..d07e0bd80f6 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -3,18 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getLanguageService as getHTMLLanguageService, DocumentContext, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; -import { - CompletionItem, Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range, - Hover, DocumentHighlight, CompletionList, Position, FormattingOptions, SymbolInformation, FoldingRange -} from 'vscode-languageserver-types'; -import { ColorInformation, ColorPresentation, Color, WorkspaceFolder } from 'vscode-languageserver'; - +import { getCSSLanguageService } from 'vscode-css-languageservice'; +import { ClientCapabilities, DocumentContext, getLanguageService as getHTMLLanguageService, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; +import { Color, ColorInformation, ColorPresentation, WorkspaceFolder } from 'vscode-languageserver'; +import { CompletionItem, CompletionList, Definition, Diagnostic, DocumentHighlight, DocumentLink, FoldingRange, FormattingOptions, Hover, Location, Position, Range, SignatureHelp, SymbolInformation, TextDocument, TextEdit } from 'vscode-languageserver-types'; import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache'; -import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; import { getCSSMode } from './cssMode'; -import { getJavaScriptMode } from './javascriptMode'; +import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; import { getHTMLMode } from './htmlMode'; +import { getJavaScriptMode } from './javascriptMode'; export { ColorInformation, ColorPresentation, Color }; @@ -66,8 +63,9 @@ export interface LanguageModeRange extends Range { attributeValue?: boolean; } -export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace, customDataProviders?: IHTMLDataProvider[]): LanguageModes { - const htmlLanguageService = getHTMLLanguageService({ customDataProviders }); +export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace, clientCapabilities: ClientCapabilities, customDataProviders?: IHTMLDataProvider[]): LanguageModes { + const htmlLanguageService = getHTMLLanguageService({ customDataProviders, clientCapabilities }); + const cssLanguageService = getCSSLanguageService({ clientCapabilities }); let documentRegions = getLanguageModelCache(10, 60, document => getDocumentRegions(htmlLanguageService, document)); @@ -77,7 +75,7 @@ export function getLanguageModes(supportedLanguages: { [languageId: string]: boo let modes = Object.create(null); modes['html'] = getHTMLMode(htmlLanguageService, workspace); if (supportedLanguages['css']) { - modes['css'] = getCSSMode(documentRegions, workspace); + modes['css'] = getCSSMode(cssLanguageService, documentRegions, workspace); } if (supportedLanguages['javascript']) { modes['javascript'] = getJavaScriptMode(documentRegions); diff --git a/extensions/html-language-features/server/src/modes/pathCompletion.ts b/extensions/html-language-features/server/src/modes/pathCompletion.ts index 7451fee1d93..b7d7c1e7220 100644 --- a/extensions/html-language-features/server/src/modes/pathCompletion.ts +++ b/extensions/html-language-features/server/src/modes/pathCompletion.ts @@ -108,11 +108,12 @@ function pathToSuggestion(p: string, valueBeforeCursor: string, fullValue: strin // Find the last slash before cursor, and calculate the start of replace range from there const valueAfterLastSlash = fullValue.slice(lastIndexOfSlash + 1); const startPos = shiftPosition(range.end, -1 - valueAfterLastSlash.length); - // If whitespace exists, replace until it - const whiteSpaceIndex = valueAfterLastSlash.indexOf(' '); + + // If whitespace exists, replace until there is no more + const whitespaceIndex = valueAfterLastSlash.indexOf(' '); let endPos; - if (whiteSpaceIndex !== -1) { - endPos = shiftPosition(startPos, whiteSpaceIndex); + if (whitespaceIndex !== -1) { + endPos = shiftPosition(startPos, whitespaceIndex); } else { endPos = shiftPosition(range.end, -1); } diff --git a/extensions/html-language-features/server/src/test/completions.test.ts b/extensions/html-language-features/server/src/test/completions.test.ts index de056ed3c1e..aaba72add6d 100644 --- a/extensions/html-language-features/server/src/test/completions.test.ts +++ b/extensions/html-language-features/server/src/test/completions.test.ts @@ -9,6 +9,7 @@ import { URI } from 'vscode-uri'; import { TextDocument, CompletionList, CompletionItemKind } from 'vscode-languageserver-types'; import { getLanguageModes } from '../modes/languageModes'; import { WorkspaceFolder } from 'vscode-languageserver'; +import { ClientCapabilities } from 'vscode-html-languageservice'; export interface ItemDescription { label: string; @@ -58,7 +59,7 @@ export function testCompletionFor(value: string, expected: { count?: number, ite let document = TextDocument.create(uri, 'html', 0, value); let position = document.positionAt(offset); - const languageModes = getLanguageModes({ css: true, javascript: true }, workspace); + const languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); const mode = languageModes.getModeAtPosition(document, position)!; let list = mode.doComplete!(document, position); diff --git a/extensions/html-language-features/server/src/test/folding.test.ts b/extensions/html-language-features/server/src/test/folding.test.ts index 3ce2816185b..e19555d568d 100644 --- a/extensions/html-language-features/server/src/test/folding.test.ts +++ b/extensions/html-language-features/server/src/test/folding.test.ts @@ -8,6 +8,7 @@ import * as assert from 'assert'; import { TextDocument } from 'vscode-languageserver'; import { getFoldingRanges } from '../modes/htmlFolding'; import { getLanguageModes } from '../modes/languageModes'; +import { ClientCapabilities } from 'vscode-css-languageservice'; interface ExpectedIndentRange { startLine: number; @@ -21,7 +22,7 @@ function assertRanges(lines: string[], expected: ExpectedIndentRange[], message? settings: {}, folders: [{ name: 'foo', uri: 'test://foo' }] }; - let languageModes = getLanguageModes({ css: true, javascript: true }, workspace); + let languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); let actual = getFoldingRanges(languageModes, document, nRanges, null); let actualRanges = []; diff --git a/extensions/html-language-features/server/src/test/formatting.test.ts b/extensions/html-language-features/server/src/test/formatting.test.ts index 702aa76da6c..8c59c75e017 100644 --- a/extensions/html-language-features/server/src/test/formatting.test.ts +++ b/extensions/html-language-features/server/src/test/formatting.test.ts @@ -11,6 +11,7 @@ import { getLanguageModes } from '../modes/languageModes'; import { TextDocument, Range, FormattingOptions } from 'vscode-languageserver-types'; import { format } from '../modes/formatting'; +import { ClientCapabilities } from 'vscode-html-languageservice'; suite('HTML Embedded Formatting', () => { @@ -19,7 +20,7 @@ suite('HTML Embedded Formatting', () => { settings: options, folders: [{ name: 'foo', uri: 'test://foo' }] }; - var languageModes = getLanguageModes({ css: true, javascript: true }, workspace); + var languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); let rangeStartOffset = value.indexOf('|'); let rangeEndOffset; diff --git a/extensions/html-language-features/server/src/utils/documentContext.ts b/extensions/html-language-features/server/src/utils/documentContext.ts index bfd26d1aa8d..6c391064fae 100644 --- a/extensions/html-language-features/server/src/utils/documentContext.ts +++ b/extensions/html-language-features/server/src/utils/documentContext.ts @@ -32,7 +32,11 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp } } } - return url.resolve(base, ref); + try { + return url.resolve(base, ref); + } catch { + return ''; + } }, }; } diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 8c532e3136f..9ea59b6077c 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -229,22 +229,23 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.2.tgz#7496e538b0c151feac16d5888cc0b1b104f4c736" - integrity sha512-pTnfXbsME3pl+yDfhUp/mtvPyIJk0Le4zqJxDn56s9GY9LqY0RmkSEh0oHH6D0HXR3Ni6wKosIaqu8a2G0+jdw== +vscode-css-languageservice@^4.0.3-next.1: + version "4.0.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.1.tgz#e89d01ce0d79b3e6c2642f5e3ad73cb8160d38d9" + integrity sha512-Zrm5TeraVUJ8vRikWhFt259dQu+WK+Ie3K5UA8BB4kqcanoM+1mcnIt8fPkTXlZLbiEWElrkJ9yuYbDNkufeBg== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" + vscode-uri "^2.0.3" -vscode-html-languageservice@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.0.tgz#b9649aa0713d68665d7546bd3772dd10e4dbe200" - integrity sha512-AgNyjaYrmgundh5gXP0bqCLeLdfUTyvNafF1moNwYdqeNh6DIpMG6RjwYwgtNChXSsVGXnaHiwGMtAUwMxkQUQ== +vscode-html-languageservice@^3.0.4-next.0: + version "3.0.4-next.0" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.0.tgz#d4f5a103b94753a19b374158212fe734dbe670e8" + integrity sha512-5Z5ITtokWt/zuPKemKEXfC+4XHoQryBAZVAcTwpAel2qqueUwGqjd5ZrVy/2x5GZAdZAipl0BvsTTMkOBS1BFQ== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" - vscode-uri "^2.0.1" + vscode-uri "^2.0.3" vscode-jsonrpc@^4.1.0-next.2: version "4.1.0-next.2" @@ -288,10 +289,10 @@ vscode-uri@^1.0.6: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== -vscode-uri@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.1.tgz#5448e4f77d21d93ffa34b96f84c6c5e09e3f5a9b" - integrity sha512-s/k0zsYr6y+tsocFyxT/+G5aq8mEdpDZuph3LZ+UmCs7LNhx/xomiCy5kyP+jOAKC7RMCUvb6JbPD1/TgAvq0g== +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== wrappy@1: version "1.0.2" diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 9ea6c3cec1b..a90d452bddf 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/3508c88a4ac6112934e0c34de7942c67682b2321", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/cf7b1ec2c20b5fe28695249596128ff514e1a659", "name": "JavaScript (with React support)", "scopeName": "source.js", "patterns": [ @@ -286,7 +286,7 @@ { "name": "meta.var.expr.js", "begin": "(?=(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(\\!)?(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js entity.name.function.js" @@ -435,7 +435,7 @@ "name": "keyword.operator.definiteassignment.js" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js variable.other.constant.js entity.name.function.js" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -1108,7 +1108,7 @@ "include": "#comment" }, { - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.js entity.name.function.js" @@ -1144,7 +1144,7 @@ "name": "keyword.operator.assignment.js" } }, - "end": "(?=$|^|[,);}\\]]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.js" @@ -1318,7 +1318,7 @@ }, { "name": "meta.method.declaration.js", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.js" @@ -1350,7 +1350,7 @@ }, "object-literal-method-declaration": { "name": "meta.method.declaration.js", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -1371,7 +1371,7 @@ "include": "#function-body" }, { - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -1431,7 +1431,7 @@ }, { "name": "meta.arrow.js", - "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2604,7 +2604,7 @@ }, { "name": "meta.object.member.js", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.js" @@ -2695,7 +2695,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2749,6 +2749,9 @@ } ] }, + { + "include": "#possibly-arrow-return-type" + }, { "include": "#expression" } @@ -2869,7 +2872,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2883,7 +2886,7 @@ ] }, { - "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2953,7 +2956,7 @@ } }, { - "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -3172,6 +3175,20 @@ "name": "keyword.operator.arithmetic.js", "match": "%|\\*|/|-|\\+" }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(/)(?![/*]))", + "end": "(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)", + "endCaptures": { + "1": { + "name": "keyword.operator.arithmetic.js" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, { "match": "(?<=[_$[:alnum:])\\]])\\s*(/)(?![/*])", "captures": { @@ -3469,7 +3486,7 @@ } }, { - "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", "captures": { "1": { "name": "punctuation.accessor.js" @@ -3541,7 +3558,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js" @@ -3753,7 +3770,7 @@ ] }, "possibly-arrow-return-type": { - "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", "beginCaptures": { "1": { "name": "meta.arrow.js meta.return.type.arrow.js keyword.operator.type.annotation.js" @@ -5297,7 +5314,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { @@ -5357,7 +5374,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 627882de1e0..067eda2d5e6 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/3508c88a4ac6112934e0c34de7942c67682b2321", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/cf7b1ec2c20b5fe28695249596128ff514e1a659", "name": "JavaScript (with React support)", "scopeName": "source.js.jsx", "patterns": [ @@ -286,7 +286,7 @@ { "name": "meta.var.expr.js.jsx", "begin": "(?=(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(\\!)?(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" @@ -435,7 +435,7 @@ "name": "keyword.operator.definiteassignment.js.jsx" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx entity.name.function.js.jsx" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -1108,7 +1108,7 @@ "include": "#comment" }, { - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.js.jsx entity.name.function.js.jsx" @@ -1144,7 +1144,7 @@ "name": "keyword.operator.assignment.js.jsx" } }, - "end": "(?=$|^|[,);}\\]]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.js.jsx" @@ -1318,7 +1318,7 @@ }, { "name": "meta.method.declaration.js.jsx", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.js.jsx" @@ -1350,7 +1350,7 @@ }, "object-literal-method-declaration": { "name": "meta.method.declaration.js.jsx", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -1371,7 +1371,7 @@ "include": "#function-body" }, { - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -1431,7 +1431,7 @@ }, { "name": "meta.arrow.js.jsx", - "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2604,7 +2604,7 @@ }, { "name": "meta.object.member.js.jsx", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.js.jsx" @@ -2695,7 +2695,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2749,6 +2749,9 @@ } ] }, + { + "include": "#possibly-arrow-return-type" + }, { "include": "#expression" } @@ -2869,7 +2872,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2883,7 +2886,7 @@ ] }, { - "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2953,7 +2956,7 @@ } }, { - "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -3172,6 +3175,20 @@ "name": "keyword.operator.arithmetic.js.jsx", "match": "%|\\*|/|-|\\+" }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(/)(?![/*]))", + "end": "(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)", + "endCaptures": { + "1": { + "name": "keyword.operator.arithmetic.js.jsx" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, { "match": "(?<=[_$[:alnum:])\\]])\\s*(/)(?![/*])", "captures": { @@ -3469,7 +3486,7 @@ } }, { - "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", "captures": { "1": { "name": "punctuation.accessor.js.jsx" @@ -3541,7 +3558,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js.jsx" @@ -3753,7 +3770,7 @@ ] }, "possibly-arrow-return-type": { - "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", "beginCaptures": { "1": { "name": "meta.arrow.js.jsx meta.return.type.arrow.js.jsx keyword.operator.type.annotation.js.jsx" @@ -5297,7 +5314,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { @@ -5357,7 +5374,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index 3515c4a8aa6..323e5f0ed94 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/.npmignore b/extensions/json-language-features/server/.npmignore index a6661ddb7fc..3032fe8b26f 100644 --- a/extensions/json-language-features/server/.npmignore +++ b/extensions/json-language-features/server/.npmignore @@ -4,4 +4,7 @@ out/**/*.js.map src/ test/ tsconfig.json -.gitignore \ No newline at end of file +.gitignore +yarn.lock +extension.webpack.config.js +vscode-json-languageserver-*.tgz \ No newline at end of file diff --git a/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md index 9b02dc24ef6..5ca997d9e12 100644 --- a/extensions/json-language-features/server/README.md +++ b/extensions/json-language-features/server/README.md @@ -21,6 +21,8 @@ The server implements the following capabilities of the language server protocol - [Document Symbols](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) for quick navigation to properties in the document. - [Document Colors](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentColor) for showing color decorators on values representing colors and [Color Presentation](https://microsoft.github.io/language-server-protocol/specification#textDocument_colorPresentation) for color presentation information to support color pickers. The location of colors is defined by the document's [JSON schema](http://json-schema.org/). All values marked with `"format": "color-hex"` (VSCode specific, non-standard JSON Schema extension) are considered color values. The supported color formats are `#rgb[a]` and `#rrggbb[aa]`. - [Code Formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) supporting ranges and formatting the whole document. +- [Folding Ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) for all folding ranges in the document. +- Semantic Selection for semantic selection for one or multiple cursor positions. - [Diagnostics (Validation)](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) are pushed for all open documents - syntax errors - structural validation based on the document's [JSON schema](http://json-schema.org/). @@ -90,10 +92,39 @@ To find the schema for a given JSON document, the server uses the following mech - The settings define a schema association based on the documents URL. Settings can either associate a schema URL to a file or path pattern, and they can directly provide a schema. - Additionally, schema associations can also be provided by a custom 'schemaAssociations' configuration call. -Schemas are identified by URLs. To load the content of a schema, the JSON language server tries to load from that URL or path. The following URL schemas are supported: +Schemas are identified by URLs. To load the content of a schema, the JSON language server either tries to load from that URI or path itself, or delegates to the client. + +The `initializationOptions.handledSchemaProtocols` initialization option defines which URLs are handled by the server. Requests for all other URIs are send to the client. + +`handledSchemaProtocols` is part of the initialization options and can't be changed while the server is running. + +```ts +let clientOptions: LanguageClientOptions = { + initializationOptions: { + handledSchemaProtocols: ['file'] // language server should only try to load file URLs + } + ... +} +``` + +If `handledSchemaProtocols` is not set, the JSON language server will load the following URLs itself: + - `http`, `https`: Loaded using NodeJS's HTTP support. Proxies can be configured through the settings. - `file`: Loaded using NodeJS's `fs` support. -- `vscode`: Loaded by an LSP call to the client. + +#### Schema content request + +Requests for schemas with URLs not handled by the server are forwarded to the client through an LSP request. This request is a JSON language server specific, non-standardized, extension to the LSP. + +Request: +- method: 'vscode/content' +- params: `string` - The schema URL to request. +- response: `string` - The content of the schema with the given URL + +#### Schema content change notification + +When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server specific, non-standardized, extension to the LSP. +The server will, as a response, clear the schema content from the cache and reload the schema content when required again. #### Schema associations notification @@ -111,20 +142,6 @@ interface ISchemaAssociations { - keys: a file names or file path (separated by `/`). `*` can be used as a wildcard. - values: An array of schema URLs -#### Schema content request - -The schema content for schema URLs that start with `vscode://` will be requested from the client through an LSP request. This request is a JSON language server specific, non-standardized, extension to the LSP. - -Request: -- method: 'vscode/content' -- params: `string` - The schema URL to request. The server will only ask for URLs that start with `vscode://` -- response: `string` - The content of the schema with the given URL - -#### Schema content change notification - -When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server specific, non-standardized, extension to the LSP. -The server will, as a response, clear the schema content from the cache and reload the schema content when required again. - Notification: - method: 'json/schemaContent' - params: `string` the URL of the schema that has changed. diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 68b639c2aae..68e6a005537 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -1,7 +1,7 @@ { "name": "vscode-json-languageserver", "description": "JSON language server", - "version": "1.0.1", + "version": "1.2.1", "author": "Microsoft Corporation", "license": "MIT", "engines": { @@ -17,17 +17,16 @@ "vscode-json-languageservice": "^3.3.0", "vscode-languageserver": "^5.3.0-next.8", "vscode-nls": "^4.1.1", - "vscode-uri": "^2.0.1" + "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", "@types/node": "^10.14.8" }, "scripts": { - "prepublishOnly": "npm run clean && npm run test", - "preversion": "npm test", - "compile": "gulp compile-extension:json-language-features-server", - "watch": "gulp watch-extension:json-language-features-server", + "prepublishOnly": "npm run clean && npm run compile", + "compile": "npx gulp compile-extension:json-language-features-server", + "watch": "npx gulp watch-extension:json-language-features-server", "clean": "../../../node_modules/.bin/rimraf out", "install-service-next": "yarn add vscode-json-languageservice@next", "install-service-local": "yarn link vscode-json-languageservice", diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index b3d5ab47b8f..ba1c7a18518 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -14,7 +14,7 @@ import * as fs from 'fs'; import { URI } from 'vscode-uri'; import * as URL from 'url'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; -import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration } from 'vscode-json-languageservice'; +import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities } from 'vscode-json-languageservice'; import { getLanguageModelCache } from './languageModelCache'; interface ISchemaAssociations { @@ -103,6 +103,7 @@ function getSchemaRequestService(handledSchemas: { [schema: string]: boolean }) let languageService = getLanguageService({ workspaceContext, contributions: [], + clientCapabilities: ClientCapabilities.LATEST }); // Create a text document manager. @@ -154,7 +155,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { documentSymbolProvider: true, documentRangeFormattingProvider: false, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; @@ -433,7 +435,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/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 1bb198a5210..13ab8c59ab0 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -134,3 +134,8 @@ vscode-uri@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.1.tgz#5448e4f77d21d93ffa34b96f84c6c5e09e3f5a9b" integrity sha512-s/k0zsYr6y+tsocFyxT/+G5aq8mEdpDZuph3LZ+UmCs7LNhx/xomiCy5kyP+jOAKC7RMCUvb6JbPD1/TgAvq0g== + +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== diff --git a/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json b/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json index f8fd1e8b49c..b94e9eba4a3 100644 --- a/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json +++ b/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json @@ -716,7 +716,7 @@ { "begin": "(^|\\G)(\\s*)(.*)", "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", - "contentName": "meta.embedded.block.cpp", + "contentName": "meta.embedded.block.cpp source.cpp", "patterns": [ { "include": "source.cpp" diff --git a/extensions/markdown-language-features/cgmanifest.json b/extensions/markdown-language-features/cgmanifest.json deleted file mode 100644 index 71df78ef41f..00000000000 --- a/extensions/markdown-language-features/cgmanifest.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "registrations": [ - { - "component": { - "type": "git", - "git": { - "name": "textmate/markdown.tmbundle", - "repositoryUrl": "https://github.com/textmate/markdown.tmbundle", - "commitHash": "11cf764606cb2cde54badb5d0e5a0758a8871c4b" - } - }, - "licenseDetail": [ - "Copyright (c) markdown.tmbundle authors", - "", - "If not otherwise specified (see below), files in this repository fall under the following license:", - "", - "Permission to copy, use, modify, sell and distribute this", - "software is granted. This software is provided \"as is\" without", - "express or implied warranty, and with no claim as to its", - "suitability for any purpose.", - "", - "An exception is made for files in readable text which contain their own license information,", - "or files where an accompanying file exists (in the same directory) with a \"-license\" suffix added", - "to the base-name name of the original file, and an extension of txt, html, or similar. For example", - "\"tidy\" is accompanied by \"tidy-license.txt\"." - ], - "license": "TextMate Bundle License", - "version": "0.0.0" - } - ], - "version": 1 -} \ No newline at end of file diff --git a/extensions/markdown-language-features/media/markdown.css b/extensions/markdown-language-features/media/markdown.css index dc12cfca001..273dc40f917 100644 --- a/extensions/markdown-language-features/media/markdown.css +++ b/extensions/markdown-language-features/media/markdown.css @@ -186,6 +186,7 @@ pre.hljs code > div { pre code { color: var(--vscode-editor-foreground); + tab-size: 4; } diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 8e841a982aa..0d74e1ac674 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": { @@ -187,6 +187,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 a916bccefc0..d61a3211e8c 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 5edc8c1eb7a..c874f5791ed 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -75,7 +75,7 @@ export class PreviewDocumentVersion { export class MarkdownPreview extends Disposable { - public static viewType = 'markdown.preview'; + public static readonly viewType = 'markdown.preview'; private _resource: vscode.Uri; private _locked: boolean; @@ -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 dda56c87172..3fc8106908b 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/npm/resources/dark/continue.svg b/extensions/npm/resources/dark/continue.svg index e6eb6041129..8b0a58eca9b 100644 --- a/extensions/npm/resources/dark/continue.svg +++ b/extensions/npm/resources/dark/continue.svg @@ -1 +1,3 @@ -continue \ No newline at end of file + + + diff --git a/extensions/npm/resources/dark/debug.svg b/extensions/npm/resources/dark/debug.svg index e211df43ef6..e4c1b7a927b 100644 --- a/extensions/npm/resources/dark/debug.svg +++ b/extensions/npm/resources/dark/debug.svg @@ -1,7 +1,5 @@ - - - - - - + + + + diff --git a/extensions/npm/resources/dark/prepostscript.svg b/extensions/npm/resources/dark/prepostscript.svg index cc9bcee715a..a8c87f2d8f6 100644 --- a/extensions/npm/resources/dark/prepostscript.svg +++ b/extensions/npm/resources/dark/prepostscript.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/extensions/npm/resources/dark/refresh.svg b/extensions/npm/resources/dark/refresh.svg index d79fdaa4e8e..ec0c43f0bc3 100644 --- a/extensions/npm/resources/dark/refresh.svg +++ b/extensions/npm/resources/dark/refresh.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/extensions/npm/resources/dark/script.svg b/extensions/npm/resources/dark/script.svg index f90781897a7..7137a9d7bb5 100644 --- a/extensions/npm/resources/dark/script.svg +++ b/extensions/npm/resources/dark/script.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/npm/resources/light/continue.svg b/extensions/npm/resources/light/continue.svg index a4dd1cd3ca8..2563bfa114b 100644 --- a/extensions/npm/resources/light/continue.svg +++ b/extensions/npm/resources/light/continue.svg @@ -1 +1,3 @@ -continue \ No newline at end of file + + + diff --git a/extensions/npm/resources/light/debug.svg b/extensions/npm/resources/light/debug.svg index b8efb1c8f77..81a5ffb6b11 100644 --- a/extensions/npm/resources/light/debug.svg +++ b/extensions/npm/resources/light/debug.svg @@ -1,7 +1,5 @@ - - - - - - + + + + diff --git a/extensions/npm/resources/light/prepostscript.svg b/extensions/npm/resources/light/prepostscript.svg index e59d80cd323..87eb59e12a6 100644 --- a/extensions/npm/resources/light/prepostscript.svg +++ b/extensions/npm/resources/light/prepostscript.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/extensions/npm/resources/light/refresh.svg b/extensions/npm/resources/light/refresh.svg index e0345748192..a5b88123a0e 100644 --- a/extensions/npm/resources/light/refresh.svg +++ b/extensions/npm/resources/light/refresh.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/extensions/npm/resources/light/script.svg b/extensions/npm/resources/light/script.svg index fb1c74cf773..60f77501db7 100644 --- a/extensions/npm/resources/light/script.svg +++ b/extensions/npm/resources/light/script.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/php/.vscodeignore b/extensions/php/.vscodeignore index 98efc0327fb..5da0ed79e46 100644 --- a/extensions/php/.vscodeignore +++ b/extensions/php/.vscodeignore @@ -4,3 +4,4 @@ out/test/** src/** tsconfig.json cgmanifest.json +.vscode \ No newline at end of file diff --git a/extensions/python/.vscodeignore b/extensions/python/.vscodeignore index f10f292ed55..4d5a14fc91e 100644 --- a/extensions/python/.vscodeignore +++ b/extensions/python/.vscodeignore @@ -3,3 +3,4 @@ src/** tsconfig.json extension.webpack.config.js cgmanifest.json +.vscode \ No newline at end of file diff --git a/extensions/ruby/package.json b/extensions/ruby/package.json index a88b790d86f..4572f2526d8 100644 --- a/extensions/ruby/package.json +++ b/extensions/ruby/package.json @@ -12,7 +12,7 @@ "contributes": { "languages": [{ "id": "ruby", - "extensions": [ ".rb", ".rbx", ".rjs", ".gemspec", ".rake", ".ru", ".erb",".podspec" ], + "extensions": [ ".rb", ".rbx", ".rjs", ".gemspec", ".rake", ".ru", ".erb", ".podspec", ".rbi" ], "filenames": [ "rakefile", "gemfile", "guardfile", "podfile", "capfile" ], "aliases": [ "Ruby", "rb" ], "firstLine": "^#!\\s*/.*\\bruby\\b", diff --git a/extensions/theme-defaults/fileicons/images/Document_16x.svg b/extensions/theme-defaults/fileicons/images/Document_16x.svg deleted file mode 100644 index 46a9f38cc88..00000000000 --- a/extensions/theme-defaults/fileicons/images/Document_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/Document_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/Document_16x_inverse.svg deleted file mode 100755 index 14abfb51077..00000000000 --- a/extensions/theme-defaults/fileicons/images/Document_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/FolderOpen_16x.svg b/extensions/theme-defaults/fileicons/images/FolderOpen_16x.svg deleted file mode 100644 index 1a3933d6351..00000000000 --- a/extensions/theme-defaults/fileicons/images/FolderOpen_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/FolderOpen_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/FolderOpen_16x_inverse.svg deleted file mode 100755 index fbf57c927f2..00000000000 --- a/extensions/theme-defaults/fileicons/images/FolderOpen_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/Folder_16x.svg b/extensions/theme-defaults/fileicons/images/Folder_16x.svg deleted file mode 100644 index 3d64ae71db4..00000000000 --- a/extensions/theme-defaults/fileicons/images/Folder_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/Folder_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/Folder_16x_inverse.svg deleted file mode 100755 index 13b18d18016..00000000000 --- a/extensions/theme-defaults/fileicons/images/Folder_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x.svg b/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x.svg deleted file mode 100755 index 20460ec997b..00000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x_inverse.svg deleted file mode 100755 index d1a0fb04b70..00000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/RootFolder_16x.svg b/extensions/theme-defaults/fileicons/images/RootFolder_16x.svg deleted file mode 100755 index 9a049f6237a..00000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolder_16x.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/RootFolder_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/RootFolder_16x_inverse.svg deleted file mode 100755 index 03721272942..00000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolder_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/document-dark.svg b/extensions/theme-defaults/fileicons/images/document-dark.svg new file mode 100644 index 00000000000..5ed5762a1f0 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/document-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/document-light.svg b/extensions/theme-defaults/fileicons/images/document-light.svg new file mode 100644 index 00000000000..ad54e13b1b1 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/document-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-dark.svg b/extensions/theme-defaults/fileicons/images/folder-dark.svg new file mode 100644 index 00000000000..43d454e7e5a --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-light.svg b/extensions/theme-defaults/fileicons/images/folder-light.svg new file mode 100644 index 00000000000..8daecdac6a3 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-open-dark.svg b/extensions/theme-defaults/fileicons/images/folder-open-dark.svg new file mode 100644 index 00000000000..6bc1c584e48 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-open-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-open-light.svg b/extensions/theme-defaults/fileicons/images/folder-open-light.svg new file mode 100644 index 00000000000..0a50339b6c8 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-open-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-dark.svg b/extensions/theme-defaults/fileicons/images/root-folder-dark.svg new file mode 100644 index 00000000000..cdb770c86a8 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-light.svg b/extensions/theme-defaults/fileicons/images/root-folder-light.svg new file mode 100644 index 00000000000..82a0294696f --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg b/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg new file mode 100644 index 00000000000..472def3daa1 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg b/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg new file mode 100644 index 00000000000..d2363bfae35 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json b/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json index 9c9f60b6efc..7a178065380 100644 --- a/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json +++ b/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json @@ -1,34 +1,34 @@ { "iconDefinitions": { "_root_folder_dark": { - "iconPath": "./images/RootFolder_16x_inverse.svg" + "iconPath": "./images/root-folder-dark.svg" }, "_root_folder_open_dark": { - "iconPath": "./images/RootFolderOpen_16x_inverse.svg" + "iconPath": "./images/root-folder-open-dark.svg" }, "_folder_dark": { - "iconPath": "./images/Folder_16x_inverse.svg" + "iconPath": "./images/folder-dark.svg" }, "_folder_open_dark": { - "iconPath": "./images/FolderOpen_16x_inverse.svg" + "iconPath": "./images/folder-open-dark.svg" }, "_file_dark": { - "iconPath": "./images/Document_16x_inverse.svg" + "iconPath": "./images/document-dark.svg" }, "_root_folder": { - "iconPath": "./images/RootFolder_16x.svg" + "iconPath": "./images/root-folder-light.svg" }, "_root_folder_open": { - "iconPath": "./images/RootFolderOpen_16x.svg" + "iconPath": "./images/root-folder-open-light.svg" }, "_folder_light": { - "iconPath": "./images/Folder_16x.svg" + "iconPath": "./images/folder-light.svg" }, "_folder_open_light": { - "iconPath": "./images/FolderOpen_16x.svg" + "iconPath": "./images/folder-open-light.svg" }, "_file_light": { - "iconPath": "./images/Document_16x.svg" + "iconPath": "./images/document-light.svg" } }, diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index c60de74fe2c..6819e853339 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -10,7 +10,7 @@ let fs = require('fs'); let https = require('https'); let url = require('url'); -// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a langauge association +// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a language association let nonBuiltInLanguages = { // { fileNames, extensions } "r": { extensions: ['r', 'rhistory', 'rprofile', 'rt'] }, "argdown": { extensions: ['ad', 'adown', 'argdown', 'argdn'] }, @@ -35,7 +35,7 @@ let nonBuiltInLanguages = { // { fileNames, extensions } "todo": { fileNames: ['todo'] } }; -let FROM_DISK = false; // set to true to take content from a repo checkedout next to the vscode repo +let FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo let font, fontMappingsFile, fileAssociationFile, colorsFile; if (!FROM_DISK) { diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json index 2b449830f50..c742c019ea3 100644 --- a/extensions/theme-seti/cgmanifest.json +++ b/extensions/theme-seti/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "seti-ui", "repositoryUrl": "https://github.com/jesseweed/seti-ui", - "commitHash": "89175d7f9e0c70cd325b80a18a3c77fc8eb7c798" + "commitHash": "904c16acced1134a81b31d71d60293288c31334b" } }, "version": "0.1.0" diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff index e590d77f684..b85727d01e4 100644 Binary files a/extensions/theme-seti/icons/seti.woff and b/extensions/theme-seti/icons/seti.woff differ diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index 4aec2074092..2b5d276a515 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -206,6 +206,14 @@ "fontCharacter": "\\E017", "fontColor": "#a074c4" }, + "_cpp_2_light": { + "fontCharacter": "\\E017", + "fontColor": "#b7b73b" + }, + "_cpp_2": { + "fontCharacter": "\\E017", + "fontColor": "#cbcb41" + }, "_crystal_light": { "fontCharacter": "\\E018", "fontColor": "#bfc2c1" @@ -246,999 +254,1103 @@ "fontCharacter": "\\E01C", "fontColor": "#cc3e44" }, - "_db_light": { + "_dart_light": { "fontCharacter": "\\E01D", + "fontColor": "#498ba7" + }, + "_dart": { + "fontCharacter": "\\E01D", + "fontColor": "#519aba" + }, + "_db_light": { + "fontCharacter": "\\E01E", "fontColor": "#dd4b78" }, "_db": { - "fontCharacter": "\\E01D", + "fontCharacter": "\\E01E", "fontColor": "#f55385" }, "_default_light": { - "fontCharacter": "\\E01E", + "fontCharacter": "\\E01F", "fontColor": "#bfc2c1" }, "_default": { - "fontCharacter": "\\E01E", + "fontCharacter": "\\E01F", "fontColor": "#d4d7d6" }, "_docker_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#498ba7" }, "_docker": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#519aba" }, "_docker_1_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#455155" }, "_docker_1": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#4d5a5e" }, "_docker_2_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#7fae42" }, "_docker_2": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#8dc149" }, "_docker_3_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#dd4b78" }, "_docker_3": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#f55385" }, "_ejs_light": { - "fontCharacter": "\\E022", + "fontCharacter": "\\E023", "fontColor": "#b7b73b" }, "_ejs": { - "fontCharacter": "\\E022", + "fontCharacter": "\\E023", "fontColor": "#cbcb41" }, "_elixir_light": { - "fontCharacter": "\\E023", + "fontCharacter": "\\E024", "fontColor": "#9068b0" }, "_elixir": { - "fontCharacter": "\\E023", + "fontCharacter": "\\E024", "fontColor": "#a074c4" }, "_elixir_script_light": { - "fontCharacter": "\\E024", + "fontCharacter": "\\E025", "fontColor": "#9068b0" }, "_elixir_script": { - "fontCharacter": "\\E024", + "fontCharacter": "\\E025", "fontColor": "#a074c4" }, "_elm_light": { - "fontCharacter": "\\E025", + "fontCharacter": "\\E026", "fontColor": "#498ba7" }, "_elm": { - "fontCharacter": "\\E025", + "fontCharacter": "\\E026", "fontColor": "#519aba" }, "_eslint_light": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#9068b0" }, "_eslint": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#a074c4" }, "_eslint_1_light": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#455155" }, "_eslint_1": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#4d5a5e" }, "_ethereum_light": { - "fontCharacter": "\\E028", + "fontCharacter": "\\E029", "fontColor": "#498ba7" }, "_ethereum": { - "fontCharacter": "\\E028", + "fontCharacter": "\\E029", "fontColor": "#519aba" }, "_f-sharp_light": { - "fontCharacter": "\\E029", + "fontCharacter": "\\E02A", "fontColor": "#498ba7" }, "_f-sharp": { - "fontCharacter": "\\E029", + "fontCharacter": "\\E02A", "fontColor": "#519aba" }, "_favicon_light": { - "fontCharacter": "\\E02A", + "fontCharacter": "\\E02B", "fontColor": "#b7b73b" }, "_favicon": { - "fontCharacter": "\\E02A", + "fontCharacter": "\\E02B", "fontColor": "#cbcb41" }, "_firebase_light": { - "fontCharacter": "\\E02B", + "fontCharacter": "\\E02C", "fontColor": "#cc6d2e" }, "_firebase": { - "fontCharacter": "\\E02B", + "fontCharacter": "\\E02C", "fontColor": "#e37933" }, "_firefox_light": { - "fontCharacter": "\\E02C", + "fontCharacter": "\\E02D", "fontColor": "#cc6d2e" }, "_firefox": { - "fontCharacter": "\\E02C", + "fontCharacter": "\\E02D", "fontColor": "#e37933" }, "_font_light": { - "fontCharacter": "\\E02E", + "fontCharacter": "\\E02F", "fontColor": "#b8383d" }, "_font": { - "fontCharacter": "\\E02E", + "fontCharacter": "\\E02F", "fontColor": "#cc3e44" }, "_git_light": { - "fontCharacter": "\\E02F", + "fontCharacter": "\\E030", "fontColor": "#3b4b52" }, "_git": { - "fontCharacter": "\\E02F", + "fontCharacter": "\\E030", "fontColor": "#41535b" }, "_go_light": { - "fontCharacter": "\\E033", + "fontCharacter": "\\E034", "fontColor": "#498ba7" }, "_go": { - "fontCharacter": "\\E033", + "fontCharacter": "\\E034", "fontColor": "#519aba" }, "_go2_light": { - "fontCharacter": "\\E034", + "fontCharacter": "\\E035", "fontColor": "#498ba7" }, "_go2": { - "fontCharacter": "\\E034", + "fontCharacter": "\\E035", "fontColor": "#519aba" }, "_gradle_light": { - "fontCharacter": "\\E035", + "fontCharacter": "\\E036", "fontColor": "#7fae42" }, "_gradle": { - "fontCharacter": "\\E035", + "fontCharacter": "\\E036", "fontColor": "#8dc149" }, "_grails_light": { - "fontCharacter": "\\E036", + "fontCharacter": "\\E037", "fontColor": "#7fae42" }, "_grails": { - "fontCharacter": "\\E036", + "fontCharacter": "\\E037", "fontColor": "#8dc149" }, + "_graphql_light": { + "fontCharacter": "\\E038", + "fontColor": "#dd4b78" + }, + "_graphql": { + "fontCharacter": "\\E038", + "fontColor": "#f55385" + }, "_grunt_light": { - "fontCharacter": "\\E037", + "fontCharacter": "\\E039", "fontColor": "#cc6d2e" }, "_grunt": { - "fontCharacter": "\\E037", + "fontCharacter": "\\E039", "fontColor": "#e37933" }, "_gulp_light": { - "fontCharacter": "\\E038", + "fontCharacter": "\\E03A", "fontColor": "#b8383d" }, "_gulp": { - "fontCharacter": "\\E038", + "fontCharacter": "\\E03A", "fontColor": "#cc3e44" }, "_haml_light": { - "fontCharacter": "\\E03A", + "fontCharacter": "\\E03C", "fontColor": "#b8383d" }, "_haml": { - "fontCharacter": "\\E03A", + "fontCharacter": "\\E03C", "fontColor": "#cc3e44" }, + "_happenings_light": { + "fontCharacter": "\\E03D", + "fontColor": "#498ba7" + }, + "_happenings": { + "fontCharacter": "\\E03D", + "fontColor": "#519aba" + }, "_haskell_light": { - "fontCharacter": "\\E03B", + "fontCharacter": "\\E03E", "fontColor": "#9068b0" }, "_haskell": { - "fontCharacter": "\\E03B", + "fontCharacter": "\\E03E", "fontColor": "#a074c4" }, "_haxe_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#cc6d2e" }, "_haxe": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#e37933" }, "_haxe_1_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#b7b73b" }, "_haxe_1": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#cbcb41" }, "_haxe_2_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#498ba7" }, "_haxe_2": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#519aba" }, "_haxe_3_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#9068b0" }, "_haxe_3": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#a074c4" }, "_heroku_light": { - "fontCharacter": "\\E03D", + "fontCharacter": "\\E040", "fontColor": "#9068b0" }, "_heroku": { - "fontCharacter": "\\E03D", + "fontCharacter": "\\E040", "fontColor": "#a074c4" }, "_hex_light": { - "fontCharacter": "\\E03E", + "fontCharacter": "\\E041", "fontColor": "#b8383d" }, "_hex": { - "fontCharacter": "\\E03E", + "fontCharacter": "\\E041", "fontColor": "#cc3e44" }, "_html_light": { - "fontCharacter": "\\E03F", - "fontColor": "#cc6d2e" + "fontCharacter": "\\E042", + "fontColor": "#498ba7" }, "_html": { - "fontCharacter": "\\E03F", + "fontCharacter": "\\E042", + "fontColor": "#519aba" + }, + "_html_1_light": { + "fontCharacter": "\\E042", + "fontColor": "#7fae42" + }, + "_html_1": { + "fontCharacter": "\\E042", + "fontColor": "#8dc149" + }, + "_html_2_light": { + "fontCharacter": "\\E042", + "fontColor": "#b7b73b" + }, + "_html_2": { + "fontCharacter": "\\E042", + "fontColor": "#cbcb41" + }, + "_html_3_light": { + "fontCharacter": "\\E042", + "fontColor": "#cc6d2e" + }, + "_html_3": { + "fontCharacter": "\\E042", "fontColor": "#e37933" }, "_html_erb_light": { - "fontCharacter": "\\E040", + "fontCharacter": "\\E043", "fontColor": "#b8383d" }, "_html_erb": { - "fontCharacter": "\\E040", + "fontCharacter": "\\E043", "fontColor": "#cc3e44" }, "_ignored_light": { - "fontCharacter": "\\E041", + "fontCharacter": "\\E044", "fontColor": "#3b4b52" }, "_ignored": { - "fontCharacter": "\\E041", + "fontCharacter": "\\E044", "fontColor": "#41535b" }, "_illustrator_light": { - "fontCharacter": "\\E042", + "fontCharacter": "\\E045", "fontColor": "#b7b73b" }, "_illustrator": { - "fontCharacter": "\\E042", + "fontCharacter": "\\E045", "fontColor": "#cbcb41" }, "_image_light": { - "fontCharacter": "\\E043", + "fontCharacter": "\\E046", "fontColor": "#9068b0" }, "_image": { - "fontCharacter": "\\E043", + "fontCharacter": "\\E046", "fontColor": "#a074c4" }, "_info_light": { - "fontCharacter": "\\E044", + "fontCharacter": "\\E047", "fontColor": "#498ba7" }, "_info": { - "fontCharacter": "\\E044", + "fontCharacter": "\\E047", "fontColor": "#519aba" }, "_ionic_light": { - "fontCharacter": "\\E045", + "fontCharacter": "\\E048", "fontColor": "#498ba7" }, "_ionic": { - "fontCharacter": "\\E045", + "fontCharacter": "\\E048", "fontColor": "#519aba" }, "_jade_light": { - "fontCharacter": "\\E046", + "fontCharacter": "\\E049", "fontColor": "#b8383d" }, "_jade": { - "fontCharacter": "\\E046", + "fontCharacter": "\\E049", "fontColor": "#cc3e44" }, "_java_light": { - "fontCharacter": "\\E047", + "fontCharacter": "\\E04A", "fontColor": "#b8383d" }, "_java": { - "fontCharacter": "\\E047", + "fontCharacter": "\\E04A", "fontColor": "#cc3e44" }, "_javascript_light": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#b7b73b" }, "_javascript": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#cbcb41" }, "_javascript_1_light": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#cc6d2e" }, "_javascript_1": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#e37933" }, "_javascript_2_light": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#498ba7" }, "_javascript_2": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#519aba" }, "_jenkins_light": { - "fontCharacter": "\\E049", + "fontCharacter": "\\E04C", "fontColor": "#b8383d" }, "_jenkins": { - "fontCharacter": "\\E049", + "fontCharacter": "\\E04C", "fontColor": "#cc3e44" }, "_jinja_light": { - "fontCharacter": "\\E04A", + "fontCharacter": "\\E04D", "fontColor": "#b8383d" }, "_jinja": { - "fontCharacter": "\\E04A", + "fontCharacter": "\\E04D", "fontColor": "#cc3e44" }, "_json_light": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#b7b73b" }, "_json": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#cbcb41" }, "_json_1_light": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#7fae42" }, "_json_1": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#8dc149" }, "_julia_light": { - "fontCharacter": "\\E04D", + "fontCharacter": "\\E050", "fontColor": "#9068b0" }, "_julia": { - "fontCharacter": "\\E04D", + "fontCharacter": "\\E050", "fontColor": "#a074c4" }, "_karma_light": { - "fontCharacter": "\\E04E", + "fontCharacter": "\\E051", "fontColor": "#7fae42" }, "_karma": { - "fontCharacter": "\\E04E", + "fontCharacter": "\\E051", "fontColor": "#8dc149" }, "_kotlin_light": { - "fontCharacter": "\\E04F", + "fontCharacter": "\\E052", "fontColor": "#cc6d2e" }, "_kotlin": { - "fontCharacter": "\\E04F", + "fontCharacter": "\\E052", "fontColor": "#e37933" }, "_less_light": { - "fontCharacter": "\\E050", + "fontCharacter": "\\E053", "fontColor": "#498ba7" }, "_less": { - "fontCharacter": "\\E050", + "fontCharacter": "\\E053", "fontColor": "#519aba" }, "_license_light": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#b7b73b" }, "_license": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#cbcb41" }, "_license_1_light": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#cc6d2e" }, "_license_1": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#e37933" }, "_license_2_light": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#b8383d" }, "_license_2": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#cc3e44" }, "_liquid_light": { - "fontCharacter": "\\E052", + "fontCharacter": "\\E055", "fontColor": "#7fae42" }, "_liquid": { - "fontCharacter": "\\E052", + "fontCharacter": "\\E055", "fontColor": "#8dc149" }, "_livescript_light": { - "fontCharacter": "\\E053", + "fontCharacter": "\\E056", "fontColor": "#498ba7" }, "_livescript": { - "fontCharacter": "\\E053", + "fontCharacter": "\\E056", "fontColor": "#519aba" }, "_lock_light": { - "fontCharacter": "\\E054", + "fontCharacter": "\\E057", "fontColor": "#7fae42" }, "_lock": { - "fontCharacter": "\\E054", + "fontCharacter": "\\E057", "fontColor": "#8dc149" }, "_lua_light": { - "fontCharacter": "\\E055", + "fontCharacter": "\\E058", "fontColor": "#498ba7" }, "_lua": { - "fontCharacter": "\\E055", + "fontCharacter": "\\E058", "fontColor": "#519aba" }, "_makefile_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#cc6d2e" }, "_makefile": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#e37933" }, "_makefile_1_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#9068b0" }, "_makefile_1": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#a074c4" }, "_makefile_2_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#627379" }, "_makefile_2": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#6d8086" }, "_makefile_3_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#498ba7" }, "_makefile_3": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#519aba" }, "_markdown_light": { - "fontCharacter": "\\E057", + "fontCharacter": "\\E05A", "fontColor": "#498ba7" }, "_markdown": { - "fontCharacter": "\\E057", + "fontCharacter": "\\E05A", "fontColor": "#519aba" }, "_maven_light": { - "fontCharacter": "\\E058", + "fontCharacter": "\\E05B", "fontColor": "#b8383d" }, "_maven": { - "fontCharacter": "\\E058", + "fontCharacter": "\\E05B", "fontColor": "#cc3e44" }, "_mdo_light": { - "fontCharacter": "\\E059", + "fontCharacter": "\\E05C", "fontColor": "#b8383d" }, "_mdo": { - "fontCharacter": "\\E059", + "fontCharacter": "\\E05C", "fontColor": "#cc3e44" }, "_mustache_light": { - "fontCharacter": "\\E05A", + "fontCharacter": "\\E05D", "fontColor": "#cc6d2e" }, "_mustache": { - "fontCharacter": "\\E05A", + "fontCharacter": "\\E05D", "fontColor": "#e37933" }, "_npm_light": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#3b4b52" }, "_npm": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#41535b" }, "_npm_1_light": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#b8383d" }, "_npm_1": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#cc3e44" }, "_npm_ignored_light": { - "fontCharacter": "\\E05D", + "fontCharacter": "\\E060", "fontColor": "#3b4b52" }, "_npm_ignored": { - "fontCharacter": "\\E05D", + "fontCharacter": "\\E060", "fontColor": "#41535b" }, "_nunjucks_light": { - "fontCharacter": "\\E05E", + "fontCharacter": "\\E061", "fontColor": "#7fae42" }, "_nunjucks": { - "fontCharacter": "\\E05E", + "fontCharacter": "\\E061", "fontColor": "#8dc149" }, "_ocaml_light": { - "fontCharacter": "\\E05F", + "fontCharacter": "\\E062", "fontColor": "#cc6d2e" }, "_ocaml": { - "fontCharacter": "\\E05F", + "fontCharacter": "\\E062", "fontColor": "#e37933" }, "_odata_light": { - "fontCharacter": "\\E060", + "fontCharacter": "\\E063", "fontColor": "#cc6d2e" }, "_odata": { - "fontCharacter": "\\E060", + "fontCharacter": "\\E063", "fontColor": "#e37933" }, + "_pddl_light": { + "fontCharacter": "\\E064", + "fontColor": "#9068b0" + }, + "_pddl": { + "fontCharacter": "\\E064", + "fontColor": "#a074c4" + }, "_pdf_light": { - "fontCharacter": "\\E061", + "fontCharacter": "\\E065", "fontColor": "#b8383d" }, "_pdf": { - "fontCharacter": "\\E061", + "fontCharacter": "\\E065", "fontColor": "#cc3e44" }, "_perl_light": { - "fontCharacter": "\\E062", + "fontCharacter": "\\E066", "fontColor": "#498ba7" }, "_perl": { - "fontCharacter": "\\E062", + "fontCharacter": "\\E066", "fontColor": "#519aba" }, "_photoshop_light": { - "fontCharacter": "\\E063", + "fontCharacter": "\\E067", "fontColor": "#498ba7" }, "_photoshop": { - "fontCharacter": "\\E063", + "fontCharacter": "\\E067", "fontColor": "#519aba" }, "_php_light": { - "fontCharacter": "\\E064", + "fontCharacter": "\\E068", "fontColor": "#9068b0" }, "_php": { - "fontCharacter": "\\E064", + "fontCharacter": "\\E068", "fontColor": "#a074c4" }, + "_plan_light": { + "fontCharacter": "\\E069", + "fontColor": "#7fae42" + }, + "_plan": { + "fontCharacter": "\\E069", + "fontColor": "#8dc149" + }, + "_platformio_light": { + "fontCharacter": "\\E06A", + "fontColor": "#cc6d2e" + }, + "_platformio": { + "fontCharacter": "\\E06A", + "fontColor": "#e37933" + }, "_powershell_light": { - "fontCharacter": "\\E065", + "fontCharacter": "\\E06B", "fontColor": "#498ba7" }, "_powershell": { - "fontCharacter": "\\E065", + "fontCharacter": "\\E06B", "fontColor": "#519aba" }, "_pug_light": { - "fontCharacter": "\\E067", + "fontCharacter": "\\E06D", "fontColor": "#b8383d" }, "_pug": { - "fontCharacter": "\\E067", + "fontCharacter": "\\E06D", "fontColor": "#cc3e44" }, "_puppet_light": { - "fontCharacter": "\\E068", + "fontCharacter": "\\E06E", "fontColor": "#b7b73b" }, "_puppet": { - "fontCharacter": "\\E068", + "fontCharacter": "\\E06E", "fontColor": "#cbcb41" }, "_python_light": { - "fontCharacter": "\\E069", + "fontCharacter": "\\E06F", "fontColor": "#498ba7" }, "_python": { - "fontCharacter": "\\E069", + "fontCharacter": "\\E06F", "fontColor": "#519aba" }, "_react_light": { - "fontCharacter": "\\E06B", + "fontCharacter": "\\E071", "fontColor": "#498ba7" }, "_react": { - "fontCharacter": "\\E06B", + "fontCharacter": "\\E071", "fontColor": "#519aba" }, + "_react_1_light": { + "fontCharacter": "\\E071", + "fontColor": "#cc6d2e" + }, + "_react_1": { + "fontCharacter": "\\E071", + "fontColor": "#e37933" + }, + "_react_2_light": { + "fontCharacter": "\\E071", + "fontColor": "#b7b73b" + }, + "_react_2": { + "fontCharacter": "\\E071", + "fontColor": "#cbcb41" + }, + "_reasonml_light": { + "fontCharacter": "\\E072", + "fontColor": "#b8383d" + }, + "_reasonml": { + "fontCharacter": "\\E072", + "fontColor": "#cc3e44" + }, "_rollup_light": { - "fontCharacter": "\\E06C", + "fontCharacter": "\\E073", "fontColor": "#b8383d" }, "_rollup": { - "fontCharacter": "\\E06C", + "fontCharacter": "\\E073", "fontColor": "#cc3e44" }, "_ruby_light": { - "fontCharacter": "\\E06D", + "fontCharacter": "\\E074", "fontColor": "#b8383d" }, "_ruby": { - "fontCharacter": "\\E06D", + "fontCharacter": "\\E074", "fontColor": "#cc3e44" }, "_rust_light": { - "fontCharacter": "\\E06E", + "fontCharacter": "\\E075", "fontColor": "#627379" }, "_rust": { - "fontCharacter": "\\E06E", + "fontCharacter": "\\E075", "fontColor": "#6d8086" }, "_salesforce_light": { - "fontCharacter": "\\E06F", + "fontCharacter": "\\E076", "fontColor": "#498ba7" }, "_salesforce": { - "fontCharacter": "\\E06F", + "fontCharacter": "\\E076", "fontColor": "#519aba" }, "_sass_light": { - "fontCharacter": "\\E070", + "fontCharacter": "\\E077", "fontColor": "#dd4b78" }, "_sass": { - "fontCharacter": "\\E070", + "fontCharacter": "\\E077", "fontColor": "#f55385" }, "_sbt_light": { - "fontCharacter": "\\E071", + "fontCharacter": "\\E078", "fontColor": "#498ba7" }, "_sbt": { - "fontCharacter": "\\E071", + "fontCharacter": "\\E078", "fontColor": "#519aba" }, "_scala_light": { - "fontCharacter": "\\E072", + "fontCharacter": "\\E079", "fontColor": "#b8383d" }, "_scala": { - "fontCharacter": "\\E072", + "fontCharacter": "\\E079", "fontColor": "#cc3e44" }, "_shell_light": { - "fontCharacter": "\\E075", + "fontCharacter": "\\E07C", "fontColor": "#455155" }, "_shell": { - "fontCharacter": "\\E075", + "fontCharacter": "\\E07C", "fontColor": "#4d5a5e" }, "_slim_light": { - "fontCharacter": "\\E076", + "fontCharacter": "\\E07D", "fontColor": "#cc6d2e" }, "_slim": { - "fontCharacter": "\\E076", + "fontCharacter": "\\E07D", "fontColor": "#e37933" }, "_smarty_light": { - "fontCharacter": "\\E077", + "fontCharacter": "\\E07E", "fontColor": "#b7b73b" }, "_smarty": { - "fontCharacter": "\\E077", + "fontCharacter": "\\E07E", "fontColor": "#cbcb41" }, "_spring_light": { - "fontCharacter": "\\E078", + "fontCharacter": "\\E07F", "fontColor": "#7fae42" }, "_spring": { - "fontCharacter": "\\E078", + "fontCharacter": "\\E07F", "fontColor": "#8dc149" }, "_stylelint_light": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#bfc2c1" }, "_stylelint": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#d4d7d6" }, "_stylelint_1_light": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#455155" }, "_stylelint_1": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#4d5a5e" }, "_stylus_light": { - "fontCharacter": "\\E07A", + "fontCharacter": "\\E081", "fontColor": "#7fae42" }, "_stylus": { - "fontCharacter": "\\E07A", + "fontCharacter": "\\E081", "fontColor": "#8dc149" }, "_sublime_light": { - "fontCharacter": "\\E07B", + "fontCharacter": "\\E082", "fontColor": "#cc6d2e" }, "_sublime": { - "fontCharacter": "\\E07B", + "fontCharacter": "\\E082", "fontColor": "#e37933" }, "_svg_light": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#9068b0" }, "_svg": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#a074c4" }, "_svg_1_light": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#498ba7" }, "_svg_1": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#519aba" }, "_swift_light": { - "fontCharacter": "\\E07D", + "fontCharacter": "\\E084", "fontColor": "#cc6d2e" }, "_swift": { - "fontCharacter": "\\E07D", + "fontCharacter": "\\E084", "fontColor": "#e37933" }, "_terraform_light": { - "fontCharacter": "\\E07E", + "fontCharacter": "\\E085", "fontColor": "#9068b0" }, "_terraform": { - "fontCharacter": "\\E07E", + "fontCharacter": "\\E085", "fontColor": "#a074c4" }, "_tex_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#498ba7" }, "_tex": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#519aba" }, "_tex_1_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#b7b73b" }, "_tex_1": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#cbcb41" }, "_tex_2_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#cc6d2e" }, "_tex_2": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#e37933" }, "_tex_3_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#bfc2c1" }, "_tex_3": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#d4d7d6" }, "_todo": { - "fontCharacter": "\\E081" + "fontCharacter": "\\E088" + }, + "_tsconfig_light": { + "fontCharacter": "\\E089", + "fontColor": "#498ba7" + }, + "_tsconfig": { + "fontCharacter": "\\E089", + "fontColor": "#519aba" }, "_twig_light": { - "fontCharacter": "\\E082", + "fontCharacter": "\\E08A", "fontColor": "#7fae42" }, "_twig": { - "fontCharacter": "\\E082", + "fontCharacter": "\\E08A", "fontColor": "#8dc149" }, "_typescript_light": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#498ba7" }, "_typescript": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#519aba" }, "_typescript_1_light": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#b7b73b" }, "_typescript_1": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#cbcb41" }, "_vala_light": { - "fontCharacter": "\\E084", + "fontCharacter": "\\E08C", "fontColor": "#627379" }, "_vala": { - "fontCharacter": "\\E084", + "fontCharacter": "\\E08C", "fontColor": "#6d8086" }, "_video_light": { - "fontCharacter": "\\E085", + "fontCharacter": "\\E08D", "fontColor": "#dd4b78" }, "_video": { - "fontCharacter": "\\E085", + "fontCharacter": "\\E08D", "fontColor": "#f55385" }, "_vue_light": { - "fontCharacter": "\\E086", + "fontCharacter": "\\E08E", "fontColor": "#7fae42" }, "_vue": { - "fontCharacter": "\\E086", + "fontCharacter": "\\E08E", "fontColor": "#8dc149" }, "_wasm_light": { - "fontCharacter": "\\E087", + "fontCharacter": "\\E08F", "fontColor": "#9068b0" }, "_wasm": { - "fontCharacter": "\\E087", + "fontCharacter": "\\E08F", "fontColor": "#a074c4" }, "_wat_light": { - "fontCharacter": "\\E088", + "fontCharacter": "\\E090", "fontColor": "#9068b0" }, "_wat": { - "fontCharacter": "\\E088", + "fontCharacter": "\\E090", "fontColor": "#a074c4" }, "_webpack_light": { - "fontCharacter": "\\E089", + "fontCharacter": "\\E091", "fontColor": "#498ba7" }, "_webpack": { - "fontCharacter": "\\E089", + "fontCharacter": "\\E091", "fontColor": "#519aba" }, "_wgt_light": { - "fontCharacter": "\\E08A", + "fontCharacter": "\\E092", "fontColor": "#498ba7" }, "_wgt": { - "fontCharacter": "\\E08A", + "fontCharacter": "\\E092", "fontColor": "#519aba" }, "_windows_light": { - "fontCharacter": "\\E08B", + "fontCharacter": "\\E093", "fontColor": "#498ba7" }, "_windows": { - "fontCharacter": "\\E08B", + "fontCharacter": "\\E093", "fontColor": "#519aba" }, "_word_light": { - "fontCharacter": "\\E08C", + "fontCharacter": "\\E094", "fontColor": "#498ba7" }, "_word": { - "fontCharacter": "\\E08C", + "fontCharacter": "\\E094", "fontColor": "#519aba" }, "_xls_light": { - "fontCharacter": "\\E08D", + "fontCharacter": "\\E095", "fontColor": "#7fae42" }, "_xls": { - "fontCharacter": "\\E08D", + "fontCharacter": "\\E095", "fontColor": "#8dc149" }, "_xml_light": { - "fontCharacter": "\\E08E", + "fontCharacter": "\\E096", "fontColor": "#cc6d2e" }, "_xml": { - "fontCharacter": "\\E08E", + "fontCharacter": "\\E096", "fontColor": "#e37933" }, "_yarn_light": { - "fontCharacter": "\\E08F", + "fontCharacter": "\\E097", "fontColor": "#498ba7" }, "_yarn": { - "fontCharacter": "\\E08F", + "fontCharacter": "\\E097", "fontColor": "#519aba" }, "_yml_light": { - "fontCharacter": "\\E090", + "fontCharacter": "\\E098", "fontColor": "#9068b0" }, "_yml": { - "fontCharacter": "\\E090", + "fontCharacter": "\\E098", "fontColor": "#a074c4" }, "_zip_light": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#b8383d" }, "_zip": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#cc3e44" }, "_zip_1_light": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#627379" }, "_zip_1": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#6d8086" } }, @@ -1249,6 +1361,10 @@ "asm": "_asm", "s": "_asm", "h": "_c_1", + "aspx": "_html", + "ascx": "_html_1", + "asax": "_html_2", + "master": "_html_2", "hh": "_cpp_1", "hpp": "_cpp_1", "hxx": "_cpp_1", @@ -1286,6 +1402,8 @@ "article": "_go", "gradle": "_gradle", "gsp": "_grails", + "gql": "_graphql", + "graphql": "_graphql", "haml": "_haml", "hs": "_haskell", "lhs": "_haskell", @@ -1297,6 +1415,7 @@ "classpath": "_java", "js.map": "_javascript", "spec.js": "_javascript_1", + "test.js": "_javascript_1", "es": "_javascript", "es5": "_javascript", "es7": "_javascript", @@ -1305,6 +1424,7 @@ "jl": "_julia", "kt": "_kotlin", "kts": "_kotlin", + "dart": "_dart", "liquid": "_liquid", "ls": "_livescript", "argdown": "_argdown", @@ -1326,10 +1446,18 @@ "cmxa": "_ocaml", "odata": "_odata", "php.inc": "_php", + "pddl": "_pddl", + "plan": "_plan", + "happenings": "_happenings", "pug": "_pug", "pp": "_puppet", "epp": "_puppet", + "spec.jsx": "_react_1", + "test.jsx": "_react_1", "cjsx": "_react", + "spec.tsx": "_react_2", + "test.tsx": "_react_2", + "re": "_reasonml", "r": "_R", "erb": "_html_erb", "erb.html": "_html_erb", @@ -1352,6 +1480,7 @@ "toml": "_config", "twig": "_twig", "spec.ts": "_typescript_1", + "test.ts": "_typescript_1", "vala": "_vala", "vapi": "_vala", "vue": "_vue", @@ -1452,6 +1581,7 @@ "gulpfile": "_gulp", "ionic.config.json": "_ionic", "ionic.project": "_ionic", + "platformio.ini": "_platformio", "rollup.config.js": "_rollup", "sass-lint.yml": "_sass", "stylelint.config.js": "_stylelint", @@ -1459,6 +1589,9 @@ "yarn.lock": "_yarn", "webpack.config.js": "_webpack", "webpack.config.build.js": "_webpack", + "webpack.common.js": "_webpack", + "webpack.dev.js": "_webpack", + "webpack.prod.js": "_webpack", "license": "_license", "licence": "_license", "copying": "_license", @@ -1475,6 +1608,7 @@ "bat": "_windows", "clojure": "_clojure", "coffeescript": "_coffee", + "jsonc": "_tsconfig", "c": "_c", "cpp": "_cpp", "csharp": "_c-sharp", @@ -1484,7 +1618,7 @@ "go": "_go2", "groovy": "_grails", "handlebars": "_mustache", - "html": "_html", + "html": "_html_3", "properties": "_java", "java": "_java", "javascriptreact": "_react", @@ -1495,12 +1629,14 @@ "makefile": "_makefile", "markdown": "_markdown", "objective-c": "_c_2", + "objective-cpp": "_cpp_2", "perl": "_perl", "php": "_php", "powershell": "_powershell", "jade": "_jade", "python": "_python", "r": "_R", + "razor": "_html", "ruby": "_ruby", "rust": "_rust", "scss": "_sass", @@ -1539,6 +1675,10 @@ "asm": "_asm_light", "s": "_asm_light", "h": "_c_1_light", + "aspx": "_html_light", + "ascx": "_html_1_light", + "asax": "_html_2_light", + "master": "_html_2_light", "hh": "_cpp_1_light", "hpp": "_cpp_1_light", "hxx": "_cpp_1_light", @@ -1576,6 +1716,8 @@ "article": "_go_light", "gradle": "_gradle_light", "gsp": "_grails_light", + "gql": "_graphql_light", + "graphql": "_graphql_light", "haml": "_haml_light", "hs": "_haskell_light", "lhs": "_haskell_light", @@ -1587,6 +1729,7 @@ "classpath": "_java_light", "js.map": "_javascript_light", "spec.js": "_javascript_1_light", + "test.js": "_javascript_1_light", "es": "_javascript_light", "es5": "_javascript_light", "es7": "_javascript_light", @@ -1595,6 +1738,7 @@ "jl": "_julia_light", "kt": "_kotlin_light", "kts": "_kotlin_light", + "dart": "_dart_light", "liquid": "_liquid_light", "ls": "_livescript_light", "argdown": "_argdown_light", @@ -1616,10 +1760,18 @@ "cmxa": "_ocaml_light", "odata": "_odata_light", "php.inc": "_php_light", + "pddl": "_pddl_light", + "plan": "_plan_light", + "happenings": "_happenings_light", "pug": "_pug_light", "pp": "_puppet_light", "epp": "_puppet_light", + "spec.jsx": "_react_1_light", + "test.jsx": "_react_1_light", "cjsx": "_react_light", + "spec.tsx": "_react_2_light", + "test.tsx": "_react_2_light", + "re": "_reasonml_light", "r": "_R_light", "erb": "_html_erb_light", "erb.html": "_html_erb_light", @@ -1642,6 +1794,7 @@ "toml": "_config_light", "twig": "_twig_light", "spec.ts": "_typescript_1_light", + "test.ts": "_typescript_1_light", "vala": "_vala_light", "vapi": "_vala_light", "vue": "_vue_light", @@ -1718,6 +1871,7 @@ "bat": "_windows_light", "clojure": "_clojure_light", "coffeescript": "_coffee_light", + "jsonc": "_tsconfig_light", "c": "_c_light", "cpp": "_cpp_light", "csharp": "_c-sharp_light", @@ -1727,7 +1881,7 @@ "go": "_go2_light", "groovy": "_grails_light", "handlebars": "_mustache_light", - "html": "_html_light", + "html": "_html_3_light", "properties": "_java_light", "java": "_java_light", "javascriptreact": "_react_light", @@ -1738,12 +1892,14 @@ "makefile": "_makefile_light", "markdown": "_markdown_light", "objective-c": "_c_2_light", + "objective-cpp": "_cpp_2_light", "perl": "_perl_light", "php": "_php_light", "powershell": "_powershell_light", "jade": "_jade_light", "python": "_python_light", "r": "_R_light", + "razor": "_html_light", "ruby": "_ruby_light", "rust": "_rust_light", "scss": "_sass_light", @@ -1801,6 +1957,7 @@ "gulpfile": "_gulp_light", "ionic.config.json": "_ionic_light", "ionic.project": "_ionic_light", + "platformio.ini": "_platformio_light", "rollup.config.js": "_rollup_light", "sass-lint.yml": "_sass_light", "stylelint.config.js": "_stylelint_light", @@ -1808,6 +1965,9 @@ "yarn.lock": "_yarn_light", "webpack.config.js": "_webpack_light", "webpack.config.build.js": "_webpack_light", + "webpack.common.js": "_webpack_light", + "webpack.dev.js": "_webpack_light", + "webpack.prod.js": "_webpack_light", "license": "_license_light", "licence": "_license_light", "copying": "_license_light", @@ -1820,5 +1980,5 @@ "npm-debug.log": "_npm_ignored_light" } }, - "version": "https://github.com/jesseweed/seti-ui/commit/89175d7f9e0c70cd325b80a18a3c77fc8eb7c798" + "version": "https://github.com/jesseweed/seti-ui/commit/904c16acced1134a81b31d71d60293288c31334b" } \ No newline at end of file diff --git a/extensions/typescript-basics/cgmanifest.json b/extensions/typescript-basics/cgmanifest.json index ffd4150e68a..cd8c1071a82 100644 --- a/extensions/typescript-basics/cgmanifest.json +++ b/extensions/typescript-basics/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "TypeScript-TmLanguage", "repositoryUrl": "https://github.com/Microsoft/TypeScript-TmLanguage", - "commitHash": "3508c88a4ac6112934e0c34de7942c67682b2321" + "commitHash": "cf7b1ec2c20b5fe28695249596128ff514e1a659" } }, "license": "MIT", diff --git a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json index a3d9b24fe96..ce5a34d5f9a 100644 --- a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/3508c88a4ac6112934e0c34de7942c67682b2321", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/11b1a4f8dc3a3eaa4df71e8cc1ad6f01a688961d", "name": "TypeScript", "scopeName": "source.ts", "patterns": [ @@ -283,7 +283,7 @@ { "name": "meta.var.expr.ts", "begin": "(?=(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(\\!)?(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts entity.name.function.ts" @@ -432,7 +432,7 @@ "name": "keyword.operator.definiteassignment.ts" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts variable.other.constant.ts entity.name.function.ts" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -1105,7 +1105,7 @@ "include": "#comment" }, { - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.ts entity.name.function.ts" @@ -1141,7 +1141,7 @@ "name": "keyword.operator.assignment.ts" } }, - "end": "(?=$|^|[,);}\\]]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.ts" @@ -1315,7 +1315,7 @@ }, { "name": "meta.method.declaration.ts", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.ts" @@ -1347,7 +1347,7 @@ }, "object-literal-method-declaration": { "name": "meta.method.declaration.ts", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -1368,7 +1368,7 @@ "include": "#function-body" }, { - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -1428,7 +1428,7 @@ }, { "name": "meta.arrow.ts", - "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2601,7 +2601,7 @@ }, { "name": "meta.object.member.ts", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.ts" @@ -2692,7 +2692,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2746,6 +2746,9 @@ } ] }, + { + "include": "#possibly-arrow-return-type" + }, { "include": "#expression" } @@ -2866,7 +2869,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2880,7 +2883,7 @@ ] }, { - "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2950,7 +2953,7 @@ } }, { - "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -3221,6 +3224,20 @@ "name": "keyword.operator.arithmetic.ts", "match": "%|\\*|/|-|\\+" }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(/)(?![/*]))", + "end": "(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)", + "endCaptures": { + "1": { + "name": "keyword.operator.arithmetic.ts" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, { "match": "(?<=[_$[:alnum:])\\]])\\s*(/)(?![/*])", "captures": { @@ -3518,7 +3535,7 @@ } }, { - "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -3590,7 +3607,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -3802,7 +3819,7 @@ ] }, "possibly-arrow-return-type": { - "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", "beginCaptures": { "1": { "name": "meta.arrow.ts meta.return.type.arrow.ts keyword.operator.type.annotation.ts" @@ -4103,7 +4120,7 @@ }, "patterns": [ { - "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))))", + "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))))", "captures": { "1": { "name": "storage.modifier.ts" diff --git a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json index 3560a374b9d..68776811480 100644 --- a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/3508c88a4ac6112934e0c34de7942c67682b2321", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/cf7b1ec2c20b5fe28695249596128ff514e1a659", "name": "TypeScriptReact", "scopeName": "source.tsx", "patterns": [ @@ -286,7 +286,7 @@ { "name": "meta.var.expr.tsx", "begin": "(?=(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(\\!)?(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx entity.name.function.tsx" @@ -435,7 +435,7 @@ "name": "keyword.operator.definiteassignment.tsx" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx variable.other.constant.tsx entity.name.function.tsx" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -1108,7 +1108,7 @@ "include": "#comment" }, { - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.tsx entity.name.function.tsx" @@ -1144,7 +1144,7 @@ "name": "keyword.operator.assignment.tsx" } }, - "end": "(?=$|^|[,);}\\]]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.tsx" @@ -1318,7 +1318,7 @@ }, { "name": "meta.method.declaration.tsx", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.tsx" @@ -1350,7 +1350,7 @@ }, "object-literal-method-declaration": { "name": "meta.method.declaration.tsx", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -1371,7 +1371,7 @@ "include": "#function-body" }, { - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -1431,7 +1431,7 @@ }, { "name": "meta.arrow.tsx", - "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2604,7 +2604,7 @@ }, { "name": "meta.object.member.tsx", - "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.tsx" @@ -2695,7 +2695,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2749,6 +2749,9 @@ } ] }, + { + "include": "#possibly-arrow-return-type" + }, { "include": "#expression" } @@ -2869,7 +2872,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2883,7 +2886,7 @@ ] }, { - "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2953,7 +2956,7 @@ } }, { - "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -3172,6 +3175,20 @@ "name": "keyword.operator.arithmetic.tsx", "match": "%|\\*|/|-|\\+" }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(/)(?![/*]))", + "end": "(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)", + "endCaptures": { + "1": { + "name": "keyword.operator.arithmetic.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, { "match": "(?<=[_$[:alnum:])\\]])\\s*(/)(?![/*])", "captures": { @@ -3469,7 +3486,7 @@ } }, { - "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -3541,7 +3558,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -3753,7 +3770,7 @@ ] }, "possibly-arrow-return-type": { - "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", "beginCaptures": { "1": { "name": "meta.arrow.tsx meta.return.type.arrow.tsx keyword.operator.type.annotation.tsx" @@ -5297,7 +5314,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { @@ -5357,7 +5374,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 25ffb4c81bd..f662cb21af6 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -34,6 +34,27 @@ function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined return undefined; } +class CloseOperation { + readonly type = 'close'; + constructor( + public readonly args: string + ) { } +} + +class OpenOperation { + readonly type = 'open'; + constructor( + public readonly args: Proto.OpenRequestArgs + ) { } +} + +class ChangeOperation { + readonly type = 'change'; + constructor( + public readonly args: Proto.FileCodeEdits + ) { } +} + /** * Manages synchronization of buffers with the TS server. * @@ -41,8 +62,7 @@ function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined */ class BufferSynchronizer { - private _pending: Proto.UpdateOpenRequestArgs = {}; - private _pendingFiles = new Set(); + private readonly _pending = new Map(); constructor( private readonly client: ITypeScriptServiceClient @@ -51,10 +71,7 @@ class BufferSynchronizer { public open(args: Proto.OpenRequestArgs) { if (this.supportsBatching) { this.updatePending(args.file, pending => { - if (!pending.openFiles) { - pending.openFiles = []; - } - pending.openFiles.push(args); + pending.set(args.file, new OpenOperation(args)); }); } else { this.client.executeWithoutWaitingForResponse('open', args); @@ -64,10 +81,7 @@ class BufferSynchronizer { public close(filepath: string) { if (this.supportsBatching) { this.updatePending(filepath, pending => { - if (!pending.closedFiles) { - pending.closedFiles = []; - } - pending.closedFiles.push(filepath); + pending.set(filepath, new CloseOperation(filepath)); }); } else { const args: Proto.FileRequestArgs = { file: filepath }; @@ -82,18 +96,14 @@ class BufferSynchronizer { if (this.supportsBatching) { this.updatePending(filepath, pending => { - if (!pending.changedFiles) { - pending.changedFiles = []; - } - - pending.changedFiles.push({ + pending.set(filepath, new ChangeOperation({ fileName: filepath, textChanges: events.map((change): Proto.CodeEdit => ({ newText: change.text, start: typeConverters.Position.toLocation(change.range.start), end: typeConverters.Position.toLocation(change.range.end), })).reverse(), // Send the edits end-of-document to start-of-document order - }); + })); }); } else { for (const { range, text } of events) { @@ -117,13 +127,23 @@ class BufferSynchronizer { private flush() { if (!this.supportsBatching) { // We've already eagerly synchronized + this._pending.clear(); return; } - if (this._pending.changedFiles || this._pending.closedFiles || this._pending.openFiles) { - this.client.executeWithoutWaitingForResponse('updateOpen', this._pending); - this._pending = {}; - this._pendingFiles.clear(); + if (this._pending.size > 0) { + const closedFiles: string[] = []; + const openFiles: Proto.OpenRequestArgs[] = []; + const changedFiles: Proto.FileCodeEdits[] = []; + for (const change of this._pending.values()) { + switch (change.type) { + case 'change': changedFiles.push(change.args); break; + case 'open': openFiles.push(change.args); break; + case 'close': closedFiles.push(change.args); break; + } + } + this.client.executeWithoutWaitingForResponse('updateOpen', { changedFiles, closedFiles, openFiles }); + this._pending.clear(); } } @@ -131,15 +151,12 @@ class BufferSynchronizer { return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get('useBatchedBufferSync', true); } - private updatePending(filepath: string, f: (pending: Proto.UpdateOpenRequestArgs) => void): void { - if (this.supportsBatching && this._pendingFiles.has(filepath)) { + private updatePending(filepath: string, f: (pending: Map) => void): void { + if (this._pending.has(filepath)) { + // we saw this file before, make sure we flush before working with it again this.flush(); - this._pendingFiles.clear(); - f(this._pending); - this._pendingFiles.add(filepath); - } else { - f(this._pending); } + f(this._pending); } } diff --git a/extensions/typescript-language-features/src/features/quickFix.ts b/extensions/typescript-language-features/src/features/quickFix.ts index 8972df52185..6ce9f199704 100644 --- a/extensions/typescript-language-features/src/features/quickFix.ts +++ b/extensions/typescript-language-features/src/features/quickFix.ts @@ -314,6 +314,7 @@ const preferredFixes = new Set([ 'forgottenThisPropertyAccess', 'spelling', 'unusedIdentifier', + 'addMissingAwait', ]); function isPreferredFix(tsAction: Proto.CodeFixAction): boolean { return preferredFixes.has(tsAction.fixName); diff --git a/extensions/typescript-language-features/src/features/task.ts b/extensions/typescript-language-features/src/features/task.ts index ae530bcdffe..d5fa55ba87a 100644 --- a/extensions/typescript-language-features/src/features/task.ts +++ b/extensions/typescript-language-features/src/features/task.ts @@ -72,6 +72,12 @@ class TscTaskProvider implements vscode.TaskProvider { } public resolveTask(_task: vscode.Task): vscode.Task | undefined { + const definition = _task.definition; + const badTsconfig = '\\tsconfig.json'; + if ((definition.tsconfig.length > badTsconfig.length) && (definition.tsconfig.substring(definition.tsconfig.length - badTsconfig.length, definition.tsconfig.length) === badTsconfig)) { + // Warn that the task has the wrong slash type + vscode.window.showWarningMessage(localize('badTsConfig', "Typescript Task in tasks.json contains \"\\\\\". Typescript tasks must use \"/\"")); + } return undefined; } diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts index a3d5690b9b9..9ea76e6a119 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts @@ -113,4 +113,31 @@ suite('commands namespace tests', () => { return Promise.all([a, b, c, d]); }); -}); \ No newline at end of file + + test('onDidExecuteCommand', async function () { + let args: any[]; + let d1 = commands.registerCommand('t1', function () { + args = [...arguments]; + }); + + + const p = new Promise((resolve, reject) => { + + let d2 = commands.onDidExecuteCommand(event => { + d2.dispose(); + d1.dispose(); + + try { + assert.equal(event.command, 't1'); + assert.deepEqual(args, event.arguments); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + + await commands.executeCommand('t1', { foo: 1 }); + await p; + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts index 80ad28ddf57..9b6c6d82897 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts @@ -195,4 +195,27 @@ suite('editor tests', () => { ); }); }); + + test('throw when using invalid edit', async function () { + + await withRandomFileEditor('foo', editor => { + + return new Promise((resolve, reject) => { + + editor.edit(edit => { + edit.insert(new Position(0, 0), 'bar'); + setTimeout(() => { + try { + edit.insert(new Position(0, 0), 'bar'); + reject(new Error('expected error')); + } catch (err) { + assert.ok(true); + resolve(); + } + }, 0); + }); + }); + }); + + }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index ad07fc997ad..dc281a06fd5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, Terminal, TerminalVirtualProcess, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode'; +import { window, Terminal, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode'; import { doesNotThrow, equal, ok } from 'assert'; suite('window namespace tests', () => { @@ -264,35 +264,16 @@ suite('window namespace tests', () => { }); term.dispose(); }); - const virtualProcess: TerminalVirtualProcess = { - onDidWrite: new EventEmitter().event - }; - window.createTerminal({ name: 'c', virtualProcess }); - }); - - test('should get dimensions event when shown', (done) => { - const reg1 = window.onDidOpenTerminal(term => { - reg1.dispose(); - equal(terminal, term); - term.show(); - }); - const virtualProcess: TerminalVirtualProcess = { + const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, - setDimensions: dimensions => { - ok(dimensions.columns > 0); - ok(dimensions.rows > 0); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); - terminal.dispose(); - } + open: () => {}, + close: () => {} }; - const terminal = window.createTerminal({ name: 'foo', virtualProcess }); + window.createTerminal({ name: 'c', pty }); }); test('should fire Terminal.onData on write', (done) => { - const reg1 = window.onDidOpenTerminal(term => { + const reg1 = window.onDidOpenTerminal(async term => { equal(terminal, term); reg1.dispose(); const reg2 = terminal.onDidWriteData(data => { @@ -304,13 +285,39 @@ suite('window namespace tests', () => { }); terminal.dispose(); }); + await startPromise; writeEmitter.fire('bar'); }); + let startResolve: () => void; + const startPromise: Promise = new Promise(r => startResolve = r); const writeEmitter = new EventEmitter(); - const virtualProcess: TerminalVirtualProcess = { - onDidWrite: writeEmitter.event + const pty: Pseudoterminal = { + onDidWrite: writeEmitter.event, + open: () => startResolve(), + close: () => {} }; - const terminal = window.createTerminal({ name: 'foo', virtualProcess }); + const terminal = window.createTerminal({ name: 'foo', pty }); + }); + + test('should fire provide dimensions on start as the terminal has been shown', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + reg1.dispose(); + }); + const pty: Pseudoterminal = { + onDidWrite: new EventEmitter().event, + open: (dimensions) => { + ok(dimensions!.columns > 0); + ok(dimensions!.rows > 0); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }, + close: () => {} + }; + const terminal = window.createTerminal({ name: 'foo', pty }); }); test('should respect dimension overrides', (done) => { @@ -333,11 +340,13 @@ suite('window namespace tests', () => { }); const writeEmitter = new EventEmitter(); const overrideDimensionsEmitter = new EventEmitter(); - const virtualProcess: TerminalVirtualProcess = { + const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, - onDidOverrideDimensions: overrideDimensionsEmitter.event + onDidOverrideDimensions: overrideDimensionsEmitter.event, + open: () => {}, + close: () => {} }; - const terminal = window.createTerminal({ name: 'foo', virtualProcess }); + const terminal = window.createTerminal({ name: 'foo', pty }); }); }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts new file mode 100644 index 00000000000..daef120762c --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as vscode from 'vscode'; + +suite('workspace-namespace', () => { + + suite('Tasks', () => { + + test('CustomExecution2 task should start and shutdown successfully', (done) => { + interface CustomTestingTaskDefinition extends vscode.TaskDefinition { + /** + * One of the task properties. This can be used to customize the task in the tasks.json + */ + customProp1: string; + } + const taskType: string = 'customTesting'; + const taskName = 'First custom task'; + const reg1 = vscode.window.onDidOpenTerminal(term => { + reg1.dispose(); + const reg2 = term.onDidWriteData(e => { + reg2.dispose(); + assert.equal(e, 'testing\r\n'); + term.dispose(); + }); + }); + const taskProvider = vscode.tasks.registerTaskProvider(taskType, { + provideTasks: () => { + const result: vscode.Task[] = []; + const kind: CustomTestingTaskDefinition = { + type: taskType, + customProp1: 'testing task one' + }; + const writeEmitter = new vscode.EventEmitter(); + const execution = new vscode.CustomExecution2((): Thenable => { + const pty: vscode.Pseudoterminal = { + onDidWrite: writeEmitter.event, + open: () => { + writeEmitter.fire('testing\r\n'); + }, + close: () => { + taskProvider.dispose(); + done(); + } + }; + return Promise.resolve(pty); + }); + const task = new vscode.Task2(kind, vscode.TaskScope.Workspace, taskName, taskType, execution); + result.push(task); + return result; + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + assert.fail('resolveTask should not trigger during the test'); + return undefined; + } + }); + vscode.commands.executeCommand('workbench.action.tasks.runTask', `${taskType}: ${taskName}`); + }); + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index dc700abdf1b..898a41247c3 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -520,6 +520,20 @@ suite('workspace-namespace', () => { }); }); + test('findFiles - null exclude', async () => { + await vscode.workspace.findFiles('**/file.txt').then((res) => { + // search.exclude folder is still searched, files.exclude folder is not + assert.equal(res.length, 1); + assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); + }); + + await vscode.workspace.findFiles('**/file.txt', null).then((res) => { + // search.exclude and files.exclude folders are both searched + assert.equal(res.length, 2); + assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); + }); + }); + test('findFiles - exclude', () => { return vscode.workspace.findFiles('**/*.png').then((res) => { assert.equal(res.length, 2); @@ -796,4 +810,29 @@ suite('workspace-namespace', () => { we.deleteFile(docUri, { ignoreIfNotExists: true }); assert.ok(await vscode.workspace.applyEdit(we)); }); + + test('The api workspace.applyEdit drops the TextEdit if there is a RenameFile later #77735', async function () { + + let [f1, f2, f3] = await Promise.all([createRandomFile(), createRandomFile(), createRandomFile()]); + + let we = new vscode.WorkspaceEdit(); + we.insert(f1, new vscode.Position(0, 0), 'f1'); + we.insert(f2, new vscode.Position(0, 0), 'f2'); + we.insert(f3, new vscode.Position(0, 0), 'f3'); + + let f1_ = nameWithUnderscore(f1); + we.renameFile(f1, f1_); + + assert.ok(await vscode.workspace.applyEdit(we)); + + assert.equal((await vscode.workspace.openTextDocument(f3)).getText(), 'f3'); + assert.equal((await vscode.workspace.openTextDocument(f2)).getText(), 'f2'); + assert.equal((await vscode.workspace.openTextDocument(f1_)).getText(), 'f1'); + try { + await vscode.workspace.fs.stat(f1); + assert.ok(false); + } catch { + assert.ok(true); + } + }); }); diff --git a/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json new file mode 100644 index 00000000000..e9f6fb82156 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "search.exclude": { + "**/search-exclude/**": true + }, + "files.exclude": { + "**/files-exclude/**": true + } +} \ No newline at end of file diff --git a/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt new file mode 100644 index 00000000000..1a010b1c0f0 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt new file mode 100644 index 00000000000..1a010b1c0f0 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json index 167df92db2d..0d93c4ea6d0 100644 --- a/extensions/vscode-test-resolver/package.json +++ b/extensions/vscode-test-resolver/package.json @@ -53,17 +53,17 @@ "statusBar/windowIndicator": [ { "command": "vscode-testresolver.newWindow", - "when": "!remoteAuthority", + "when": "!remoteName", "group": "9_local_testresolver@2" }, { "command": "vscode-testresolver.showLog", - "when": "remoteAuthority =~ /^test\\+.*$/", + "when": "remoteName == test", "group": "1_remote_testresolver_open@3" }, { "command": "vscode-testresolver.newWindow", - "when": "remoteAuthority =~ /^test\\+.*$/", + "when": "remoteName == test", "group": "1_remote_testresolver_open@1" } ] diff --git a/extensions/xml/package.json b/extensions/xml/package.json index 2e6cc49fd65..d76a632b10c 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/extensions/xml/xml.language-configuration.json b/extensions/xml/xml.language-configuration.json index faaa59c1cd3..702b6dc6eb7 100644 --- a/extensions/xml/xml.language-configuration.json +++ b/extensions/xml/xml.language-configuration.json @@ -1,31 +1,34 @@ { "comments": { - "lineComment": "", - "blockComment": [""] + "blockComment": [ "" ] }, "brackets": [ - ["<", ">"] + [""], + ["<", ">"], + ["{", "}"], + ["(", ")"] ], "autoClosingPairs": [ - ["<", ">"], - ["'", "'"], - ["\"", "\""] + { "open": "{", "close": "}"}, + { "open": "[", "close": "]"}, + { "open": "(", "close": ")" }, + { "open": "'", "close": "'" }, + { "open": "\"", "close": "\"" }, + { "open": "", "notIn": [ "comment", "string" ]}, + { "open": "", "close": "", "notIn": [ "comment", "string" ]} ], "surroundingPairs": [ - ["<", ">"], - ["'", "'"], - ["\"", "\""] - ] - - // enhancedBrackets: [{ - // tokenType: 'tag.tag-$1.xml', - // openTrigger: '>', - // open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i, - // closeComplete: '', - // closeTrigger: '>', - // close: /<\/(\w[\w\d]*)\s*>$/i - // }], - - // autoClosingPairs: [['\'', '\''], ['"', '"'] ] - + { "open": "'", "close": "'" }, + { "open": "\"", "close": "\"" }, + { "open": "{", "close": "}"}, + { "open": "[", "close": "]"}, + { "open": "(", "close": ")" }, + { "open": "<", "close": ">" } + ], + "folding": { + "markers": { + "start": "^\\s*", + "end": "^\\s*" + } + } } diff --git a/extensions/yaml/.gitignore b/extensions/yaml/.gitignore deleted file mode 100644 index 3c3629e647f..00000000000 --- a/extensions/yaml/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/package.json b/package.json index 4238c6d83ac..704ac9da679 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.37.0", - "distro": "a46b5fbf6a668c67b5ffbcdb346eb1e648f0b543", + "distro": "7224ab1f6e8484664148ab7362432b49c653d047", "author": { "name": "Microsoft Corporation" }, @@ -29,38 +29,37 @@ }, "dependencies": { "applicationinsights": "1.0.8", - "getmac": "1.4.1", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "iconv-lite": "0.5.0", "jschardet": "1.6.0", - "keytar": "4.2.1", + "keytar": "^4.11.0", "minimist": "1.2.0", "native-is-elevated": "^0.2.1", "native-keymap": "2.0.0", "native-watchdog": "1.0.0", - "node-pty": "0.9.0-beta17", + "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", "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.5", "vscode-sqlite3": "4.0.8", - "vscode-textmate": "^4.1.1", - "xterm": "3.15.0-beta70", - "xterm-addon-search": "0.2.0-beta2", + "vscode-textmate": "^4.2.2", + "xterm": "3.15.0-beta89", + "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, "devDependencies": { "7zip": "0.0.6", - "@types/keytar": "^4.0.1", + "@types/keytar": "^4.4.0", "@types/minimist": "^1.2.0", "@types/mocha": "2.2.39", "@types/node": "^10.12.12", @@ -84,7 +83,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", @@ -95,7 +94,7 @@ "gulp-gunzip": "^1.0.0", "gulp-json-editor": "^2.5.0", "gulp-plumber": "^1.2.0", - "gulp-remote-src": "^0.4.4", + "gulp-remote-retry-src": "^0.6.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", @@ -108,7 +107,11 @@ "husky": "^0.13.1", "innosetup": "5.6.1", "is": "^3.1.0", - "istanbul": "^0.3.17", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.6", "jsdom-no-contextify": "^3.1.0", "lazy.js": "^0.4.2", "merge-options": "^1.0.1", @@ -123,7 +126,6 @@ "pump": "^1.0.1", "queue": "3.0.6", "rcedit": "^1.1.0", - "remap-istanbul": "^0.13.0", "rimraf": "^2.2.8", "sinon": "^1.17.2", "source-map": "^0.4.4", @@ -152,8 +154,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-process-tree": "0.2.3" + "windows-foreground-love": "0.2.0", + "windows-mutex": "0.3.0", + "windows-process-tree": "0.2.4" } } diff --git a/remote/package.json b/remote/package.json index 291b4bde809..34ffee1a4be 100644 --- a/remote/package.json +++ b/remote/package.json @@ -9,20 +9,19 @@ "https-proxy-agent": "^2.2.1", "iconv-lite": "0.5.0", "jschardet": "1.6.0", - "keytar": "4.2.1", "minimist": "1.2.0", "native-watchdog": "1.0.0", - "node-pty": "0.9.0-beta17", + "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-textmate": "^4.1.1", - "xterm": "3.15.0-beta70", - "xterm-addon-search": "0.2.0-beta2", + "vscode-ripgrep": "^1.5.5", + "vscode-textmate": "^4.2.2", + "xterm": "3.15.0-beta89", + "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", "yazl": "^2.4.3" diff --git a/remote/web/.yarnrc b/remote/web/.yarnrc new file mode 100644 index 00000000000..b28191e6bae --- /dev/null +++ b/remote/web/.yarnrc @@ -0,0 +1,3 @@ +disturl "http://nodejs.org/dist" +target "10.11.0" +runtime "node" diff --git a/remote/web/package.json b/remote/web/package.json new file mode 100644 index 00000000000..c7a487b6c2d --- /dev/null +++ b/remote/web/package.json @@ -0,0 +1,12 @@ +{ + "name": "vscode-web", + "version": "0.0.0", + "dependencies": { + "onigasm-umd": "^2.2.2", + "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", + "semver-umd": "^5.5.3" + } + } \ No newline at end of file diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock new file mode 100644 index 00000000000..b624eb37290 --- /dev/null +++ b/remote/web/yarn.lock @@ -0,0 +1,47 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +nan@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +onigasm-umd@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" + integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== + +oniguruma@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af" + integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA== + 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" + integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== + dependencies: + oniguruma "^7.2.0" + +xterm-addon-search@0.2.0-beta2: + version "0.2.0-beta2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" + integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== + +xterm-addon-web-links@0.1.0-beta10: + version "0.1.0-beta10" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" + integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== + +xterm@3.15.0-beta67: + version "3.15.0-beta67" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta67.tgz#71973e174bdc08df620945eecd3f87912f1ac550" + integrity sha512-qLfo9GHVlu/IxgDI3vRGObWZM7UL4eLhMfjZhprx2aXNMpzmrOW6l3JDRsCjUWm93EoVavbULtnDhGSiTlKitQ== diff --git a/remote/yarn.lock b/remote/yarn.lock index 98ea4a5acd8..1c4e700f495 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -16,16 +16,6 @@ agent-base@~4.2.0: dependencies: es6-promisify "^5.0.0" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - applicationinsights@1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" @@ -35,19 +25,6 @@ applicationinsights@1.0.8: diagnostic-channel-publishers "0.2.1" zone.js "0.7.6" -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -108,14 +85,6 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - braces@^2.3.1, braces@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" @@ -132,29 +101,11 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -buffer-alloc-unsafe@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz#ffe1f67551dd055737de253337bfe853dfab1a6a" - integrity sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo= - -buffer-alloc@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.1.0.tgz#05514d33bf1656d3540c684f65b1202e90eca303" - integrity sha1-BVFNM78WVtNUDGhPZbEgLpDsowM= - dependencies: - buffer-alloc-unsafe "^0.1.0" - buffer-fill "^0.1.0" - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -buffer-fill@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-0.1.1.tgz#76d825c4d6e50e06b7a31eb520c04d08cc235071" - integrity sha512-YgBMBzdRLEfgxJIGu2wrvI2E03tMCFU1p7d1KhB4BOoMN0VxmTFjSyN5JtKt9z8Z9JajMHruI6SE25W96wNv7Q== - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -170,11 +121,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -185,11 +131,6 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -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" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -203,11 +144,6 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -237,18 +173,6 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -271,16 +195,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - diagnostic-channel-publishers@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" @@ -314,13 +228,6 @@ editions@^2.1.0, editions@^2.1.2: errlop "^1.1.1" semver "^5.6.0" -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" - integrity sha1-epDYM+/abPpurA9JSduw+tOmMgY= - dependencies: - once "^1.4.0" - errlop@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.1.tgz#d9ae4c76c3e64956c5d79e6e035d6343bfd62250" @@ -353,11 +260,6 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-template@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.1.tgz#981f188c0c3a87d2e28f559bc541426ff94f21dd" - integrity sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg== - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -430,11 +332,6 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-constants@^1.0.0: - version "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@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -444,20 +341,6 @@ fs-extra@^7.0.0: jsonfile "^4.0.0" universalify "^0.1.0" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -471,11 +354,6 @@ getmac@1.4.1: editions "^1.3.4" extract-opts "^3.2.0" -github-from-package@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" - integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= - glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -494,11 +372,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.6: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -563,11 +436,6 @@ inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" - integrity sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4= - ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -653,18 +521,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -727,14 +583,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -keytar@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.2.1.tgz#8a06a6577fdf6373e0aa6b112277e63dec77fd12" - integrity sha1-igamV3/fY3PgqmsRInfmPex3/RI= - dependencies: - nan "2.8.0" - prebuild-install "^2.4.1" - kind-of@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" @@ -807,17 +655,12 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -mimic-response@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" - integrity sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4= - minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@1.2.0, minimist@^1.2.0: +minimist@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -842,11 +685,6 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -nan@2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" - integrity sha1-7XFfP+neArV6XmJS2QqWZ14fCFo= - nan@^2.0.0, nan@^2.12.1, nan@^2.13.2, nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" @@ -874,45 +712,23 @@ native-watchdog@1.0.0: resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.0.0.tgz#97344e83cd6815a8c8e6c44a52e7be05832e65ca" integrity sha512-HKQATz5KLUMPyQQ/QaalzgTXaGz2plYPBxjyalaR4ECIu/UznXY8YJD+a9SLkkcvtxnJ8/zHLY3xik06vUZ7uA== -node-abi@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.4.1.tgz#7628c4d4ec4e9cd3764ceb3652f36b2e7f8d4923" - integrity sha512-pUlswqpHQ7zGPI9lGjZ4XDNIEUDbHxsltfIRb7dTnYdhgHWHOcB0MLZKLoCz6UMcGzSPG5wGl1HODZVQAUsH6w== - dependencies: - semver "^5.4.1" - node-addon-api@1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== -node-pty@0.9.0-beta17: - version "0.9.0-beta17" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta17.tgz#9b490df86a8124dea595e9fbedeaaf4b2eedbbcb" - integrity sha512-E94XwIs3JxLKAboquHY9Kytbbj/T/tJtRpQoAUdfPE7UXRta/NV+xdmRNhZkeU9jCji+plm656GbYFievgNPkQ== +node-pty@0.9.0-beta19: + version "0.9.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta19.tgz#0fd381b2006f4665c4c2ee0509219e591842371a" + integrity sha512-MkKEvBnauGnzgXNr/oaoWQLVXm1gheIKZs4YQp8883ZiETmbEnpSvD0FU3bELcPXG5VFPRqIGsQJ4KUMBLzkPA== dependencies: nan "^2.13.2" -noop-logger@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" - integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npmlog@^4.0.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - nsfw@1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/nsfw/-/nsfw-1.2.5.tgz#febe581af616f7b042f89df133abe62416c4c803" @@ -923,16 +739,6 @@ nsfw@1.2.5: lodash.isundefined "^3.0.1" nan "^2.0.0" -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -956,29 +762,17 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - onigasm-umd@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== -oniguruma@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.1.0.tgz#106ddf7eb42507d0442ac68b187c4f7fdf052c83" - integrity sha512-mV+6HcDNQ38vM8HVKM+MJyXO4EtSigwIZhq023A4rA8Am4dMlGhUkPwudDykExYR45oLrssR/Ep7PZCQ1OM3pA== +oniguruma@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af" + integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA== dependencies: - nan "^2.12.1" - -os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + nan "^2.14.0" pascalcase@^0.1.1: version "0.1.1" @@ -1010,63 +804,11 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -prebuild-install@^2.4.1: - version "2.5.3" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.5.3.tgz#9f65f242782d370296353710e9bc843490c19f69" - integrity sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g== - dependencies: - detect-libc "^1.0.3" - expand-template "^1.0.2" - github-from-package "0.0.0" - minimist "^1.2.0" - mkdirp "^0.5.1" - node-abi "^2.2.0" - noop-logger "^0.1.1" - npmlog "^4.0.1" - os-homedir "^1.0.1" - pump "^2.0.1" - rc "^1.1.6" - simple-get "^2.7.0" - tar-fs "^1.13.0" - tunnel-agent "^0.6.0" - which-pm-runs "^1.0.0" - process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - -pump@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" - integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -rc@^1.1.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - readable-stream@^2.0.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" @@ -1080,19 +822,6 @@ readable-stream@^2.0.2: string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -1130,7 +859,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== @@ -1147,26 +876,21 @@ 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.4.1, 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" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -1177,25 +901,6 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -simple-concat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" - integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= - -simple-get@^2.7.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" - integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== - dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" - smart-buffer@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" @@ -1292,23 +997,6 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -1316,60 +1004,6 @@ string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -tar-fs@^1.13.0: - version "1.16.2" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.2.tgz#17e5239747e399f7e77344f5f53365f04af53577" - integrity sha512-LdknWjPEiZC1nOBwhv0JBzfJBGPJar08dZg2rwZe0ZTLQoRGEzgrl7vF3qUEkCHpI/wN9e7RyCuDhMsJUCLPPQ== - dependencies: - chownr "^1.0.1" - mkdirp "^0.5.1" - pump "^1.0.0" - tar-stream "^1.1.2" - -tar-stream@^1.1.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395" - integrity sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.1.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.0" - xtend "^4.0.0" - -to-buffer@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -1395,13 +1029,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - typechecker@^4.3.0: version "4.7.0" resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.7.0.tgz#5249f427358f45b7250c4924fd4d01ed9ba435e9" @@ -1496,17 +1123,17 @@ 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.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" + integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== -vscode-textmate@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.1.1.tgz#857e836fbc13a376ec624242437e1747d79610a9" - integrity sha512-xBjq9LH6fMhWDhIVkbKlB1JeCu6lT3FI/QKN24Xi4RKPBUm16IhHTqs6Q6SUGewkNsFZGkb1tJdZsuMnlmVpgw== +vscode-textmate@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" + integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== dependencies: - oniguruma "^7.0.0" + oniguruma "^7.2.0" vscode-windows-ca-certs@0.1.0: version "0.1.0" @@ -1522,42 +1149,20 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" -which-pm-runs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" - integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= - -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== xterm-addon-web-links@0.1.0-beta10: version "0.1.0-beta10" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta70: - version "3.15.0-beta70" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta70.tgz#3e81f32e8cd7147f9a0764fbe2599c277c697a74" - integrity sha512-VXhEbWwaxrs9Ac2KuTCmGX7Ktd0V+rVF5sdjXBsq/KBCtnUdwNzKnEjamNPsoNTDUv9y93INEbq82X7iBs1Gwg== +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/completions/zsh/_code b/resources/completions/zsh/_code index 054ab351e91..265c199f62f 100644 --- a/resources/completions/zsh/_code +++ b/resources/completions/zsh/_code @@ -17,6 +17,7 @@ arguments=( '(- *)'{--telemetry}'[Shows all telemetry events which VS code collects.]' '--extensions-dir[set the root path for extensions]:root path:_directories' '--list-extensions[list the installed extensions]' + '--category[filters instaled extension list by category, when using --list-extension]' '--show-versions[show versions of installed extensions, when using --list-extension]' '--install-extension[install an extension]:id or path:_files -g "*.vsix(-.)"' '--uninstall-extension[uninstall an extension]:id or path:_files -g "*.vsix(-.)"' diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 5d92383c496..23a5afe8e71 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. @@ -11,7 +11,7 @@ VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")" ELECTRON="$VSCODE_PATH/$NAME.exe" if grep -qi Microsoft /proc/version; then # in a wsl shell - if ! [ -z "$WSL_DISTRO_NAME" ]; then + if [ "$WSL_DISTRO_NAME" ]; then # $WSL_DISTRO_NAME is available since WSL builds 18362, also for WSL2 WSL_BUILD=18362 else @@ -26,21 +26,17 @@ if grep -qi Microsoft /proc/version; then # WSLPATH is available since WSL build 17046 # WSLENV is available since WSL build 17063 export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV + CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js") # use the Remote WSL extension if installed - pushd "$VSCODE_PATH" > /dev/null WSL_EXT_ID="ms-vscode-remote.remote-wsl" - WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ELECTRON" ".\resources\app\out\cli.js" --locate-extension $WSL_EXT_ID) - popd > /dev/null - - if ! [ -z "$WSL_EXT_WLOC" ]; then + WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID) + if [ -n "$WSL_EXT_WLOC" ]; then # replace \r\n with \n in WSL_EXT_WLOC WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh WIN_CODE_CMD=$(wslpath -w "$VSCODE_PATH/bin/$APP_NAME.cmd") "$WSL_CODE" "$COMMIT" "$QUALITY" "$WIN_CODE_CMD" "$APP_NAME" "$DATAFOLDER" "$@" exit $? - else - CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js") fi else # If running under older WSL, don't pass cli.js to Electron as diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index c52a879c36f..5be0ac0e3fe 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 4.2.5 +// Type definitions for Electron 4.2.7 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -3479,14 +3479,14 @@ declare namespace Electron { * Creates a new NativeImage instance from the NSImage that maps to the given image * name. See NSImageName for a list of possible values. The hslShift is applied to * the image with the following rules This means that [-1, 0, 1] will make the - * image completely white and [-1, 1, 0] will make the image completely black. In - * some cases, the NSImageName doesn't match its string representation; one example - * of this is NSFolderImageName, whose string representation would actually be - * NSFolder. Therefore, you'll need to determine the correct string representation - * for your image before passing it in. This can be done with the following: echo - * -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | - * clang -otest -x objective-c -framework Cocoa - && ./test where SYSTEM_IMAGE_NAME - * should be replaced with any value from this list. + * image completely white and [-1, 1, 0] will make the image completely black. In + * some cases, the NSImageName doesn't match its string representation; one example + * of this is NSFolderImageName, whose string representation would actually be + * NSFolder. Therefore, you'll need to determine the correct string representation + * for your image before passing it in. This can be done with the following: echo + * -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | + * clang -otest -x objective-c -framework Cocoa - && ./test where SYSTEM_IMAGE_NAME + * should be replaced with any value from this list. */ static createFromNamedImage(imageName: string, hslShift: number[]): NativeImage; /** @@ -3737,6 +3737,17 @@ declare namespace Electron { once(event: 'unlock-screen', listener: Function): this; addListener(event: 'unlock-screen', listener: Function): this; removeListener(event: 'unlock-screen', listener: Function): this; + /** + * Calculate the system idle state. idleThreshold is the amount of time (in + * seconds) before considered idle. callback will be called synchronously on some + * systems and with an idleState argument that describes the system's state. locked + * is available on supported systems only. + */ + querySystemIdleState(idleThreshold: number, callback: (idleState: 'active' | 'idle' | 'locked' | 'unknown') => void): void; + /** + * Calculate system idle time in seconds. + */ + querySystemIdleTime(callback: (idleTime: number) => void): void; } interface PowerSaveBlocker extends EventEmitter { @@ -4418,30 +4429,6 @@ declare namespace Electron { * The new RGBA color the user assigned to be their system accent color. */ newColor: string) => void): this; - /** - * NOTE: This event is only emitted after you have called - * startAppLevelAppearanceTrackingOS - */ - on(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; - once(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; - addListener(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; - removeListener(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; on(event: 'color-changed', listener: (event: Event) => void): this; once(event: 'color-changed', listener: (event: Event) => void): this; addListener(event: 'color-changed', listener: (event: Event) => void): this; @@ -8789,17 +8776,33 @@ declare namespace Electron { * The type of media access being requested, can be video, audio or unknown */ mediaType: ('video' | 'audio' | 'unknown'); + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; } interface PermissionRequestHandlerDetails { /** * The url of the openExternal request. */ - externalURL: string; + externalURL?: string; /** * The types of media access being requested, elements can be video or audio */ - mediaTypes: Array<'video' | 'audio'>; + mediaTypes?: Array<'video' | 'audio'>; + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; } interface PluginCrashedEvent extends Event { diff --git a/src/typings/getmac.d.ts b/src/typings/semver-umd.d.ts similarity index 69% rename from src/typings/getmac.d.ts rename to src/typings/semver-umd.d.ts index e93b8135456..372f000c617 100644 --- a/src/typings/getmac.d.ts +++ b/src/typings/semver-umd.d.ts @@ -3,10 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -declare module getmac { - export function getMac(callback: (error: Error, macAddress: string) => void): void; -} +declare module 'semver-umd' { + + export * from "semver"; -declare module 'getmac' { - export = getmac; } \ No newline at end of file diff --git a/src/typings/vscode-textmate.d.ts b/src/typings/vscode-textmate.d.ts index 224b9100482..835b33008ac 100644 --- a/src/typings/vscode-textmate.d.ts +++ b/src/typings/vscode-textmate.d.ts @@ -30,7 +30,7 @@ declare module "vscode-textmate" { */ export interface RegistryOptions { theme?: IRawTheme; - loadGrammar(scopeName: string): Thenable | null; + loadGrammar(scopeName: string): Thenable; getInjections?(scopeName: string): string[]; getOnigLib?(): Thenable; } @@ -85,7 +85,7 @@ declare module "vscode-textmate" { * Load the grammar for `scopeName` and all referenced included grammars asynchronously. */ loadGrammar(initialScopeName: string): Thenable; - private _loadGrammar(initialScopeName, initialLanguage, embeddedLanguages, tokenTypes); + private _loadGrammar; /** * Adds a rawGrammar. */ @@ -182,7 +182,7 @@ declare module "vscode-textmate" { equals(other: StackElement): boolean; } export const INITIAL: StackElement; - export const parseRawGrammar: (content: string, filePath: string) => IRawGrammar; + export const parseRawGrammar: (content: string, filePath?: string) => IRawGrammar; export interface ILocation { readonly filename: string; readonly line: number; diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index b41d12219a9..663b997022b 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -15,6 +15,11 @@ declare module 'xterm' { */ export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + /** + * A string representing log level. + */ + export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off'; + /** * A string representing a renderer type. */ @@ -107,6 +112,18 @@ declare module 'xterm' { */ lineHeight?: number; + /** + * What log level to use, this will log for all levels below and including + * what is set: + * + * 1. debug + * 2. info (default) + * 3. warn + * 4. error + * 5. off + */ + logLevel?: LogLevel; + /** * Whether to treat option as the meta key. */ @@ -177,6 +194,12 @@ declare module 'xterm' { * not whitespace. */ windowsMode?: boolean; + + /** + * A string containing all characters that are considered word separated by the + * double click to select work logic. + */ + wordSeparator?: string; } /** @@ -191,7 +214,7 @@ declare module 'xterm' { cursor?: string, /** The accent color of the cursor (fg color for a block cursor) */ cursorAccent?: string, - /** The selection color (can be transparent) */ + /** The selection background color (can be transparent) */ selection?: string, /** ANSI black (eg. `\x1b[30m`) */ black?: string, @@ -483,12 +506,14 @@ declare module 'xterm' { * final character (e.g "m" for SGR) of the CSI sequence. * @param callback The function to handle the escape sequence. The callback * is called with the numerical params, as well as the special characters - * (e.g. "$" for DECSCPP). Return true if the sequence was handled; false if + * (e.g. "$" for DECSCPP). If the sequence has subparams the array will + * contain subarrays with their numercial values. + * Return true if the sequence was handled; false if * we should try a previous handler (set by addCsiHandler or setCsiHandler). * The most recently-added handler is tried first. * @return An IDisposable you can call to remove this handler. */ - addCsiHandler(flag: string, callback: (params: number[], collect: string) => boolean): IDisposable; + addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable; /** * (EXPERIMENTAL) Adds a handler for OSC escape sequences. @@ -668,12 +693,12 @@ declare module 'xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'rendererType' | 'termName'): string; + getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; /** * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean; + getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -700,13 +725,19 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'fontFamily' | 'termName' | 'bellSound', value: string): void; + setOption(key: 'fontFamily' | 'termName' | 'bellSound' | 'wordSeparator', value: string): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. */ setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'logLevel', value: LogLevel): void; /** * Sets an option on the terminal. * @param key The option key. @@ -724,7 +755,7 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; + setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key. @@ -929,16 +960,16 @@ declare module 'xterm' { // Modifications to official .d.ts below declare module 'xterm' { interface TerminalCore { - debug: boolean; - - handler(text: string): void; - _onScroll: IEventEmitter; _onKey: IEventEmitter<{ key: string }>; _charSizeService: { width: number; height: number; + }; + + _coreService: { + triggerDataEvent(data: string, wasUserInput?: boolean): void; } _renderService: { diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index b447e0b68ec..6d4436c23eb 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -122,7 +122,7 @@ export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); export const isIPad = (userAgent.indexOf('iPad') >= 0); export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0); -export const isStandalone = (window.matchMedia('(display-mode: standalone)').matches); +export const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); export function hasClipboardSupport() { if (isIE) { diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 2ea764a81e1..fa12f629000 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -34,7 +34,7 @@ export function isInDOM(node: Node | null): boolean { if (node === document.body) { return true; } - node = node.parentNode; + node = node.parentNode || (node as ShadowRoot).host; } return false; } @@ -806,7 +806,8 @@ export function createCSSRule(selector: string, cssText: string, style: HTMLStyl if (!style || !cssText) { return; } - style.textContent = `${selector}{${cssText}}\n${style.textContent}`; + + (style.sheet).insertRule(selector + '{' + cssText + '}', 0); } export function removeCSSRulesContainingSelector(ruleName: string, style: HTMLStyleElement = getSharedStyleSheet()): void { @@ -1199,7 +1200,7 @@ export function asDomUri(uri: URI): URI { if (Schemas.vscodeRemote === uri.scheme) { // rewrite vscode-remote-uris to uris of the window location // so that they can be intercepted by the service worker - return _location.with({ path: '/vscode-resources/fetch', query: uri.toString() }); + return _location.with({ path: '/vscode-resources/fetch', query: `u=${JSON.stringify(uri)}` }); } return uri; } diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index 68fe5d89e22..4506912e178 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { escape } from 'vs/base/common/strings'; -import { removeMarkdownEscapes, IMarkdownString } from 'vs/base/common/htmlContent'; +import { removeMarkdownEscapes, IMarkdownString, parseHrefAndDimensions } from 'vs/base/common/htmlContent'; import * as marked from 'vs/base/common/marked/marked'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -100,29 +100,11 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions const renderer = new marked.Renderer(); renderer.image = (href: string, title: string, text: string) => { - href = _href(href, true); let dimensions: string[] = []; - if (href) { - const splitted = href.split('|').map(s => s.trim()); - href = splitted[0]; - const parameters = splitted[1]; - if (parameters) { - const heightFromParams = /height=(\d+)/.exec(parameters); - const widthFromParams = /width=(\d+)/.exec(parameters); - const height = heightFromParams ? heightFromParams[1] : ''; - const width = widthFromParams ? widthFromParams[1] : ''; - const widthIsFinite = isFinite(parseInt(width)); - const heightIsFinite = isFinite(parseInt(height)); - if (widthIsFinite) { - dimensions.push(`width="${width}"`); - } - if (heightIsFinite) { - dimensions.push(`height="${height}"`); - } - } - } let attributes: string[] = []; if (href) { + ({ href, dimensions } = parseHrefAndDimensions(href)); + href = _href(href, true); attributes.push(`src="${href}"`); } if (text) { diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index dee572ce892..4c7295e3b9b 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -160,6 +160,8 @@ export class StandardWheelEvent { this.deltaY = e1.wheelDeltaY / 120; } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { this.deltaY = -e2.detail / 3; + } else { + this.deltaY = -e.deltaY / 40; } // horizontal delta scroll @@ -171,6 +173,8 @@ export class StandardWheelEvent { } } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { this.deltaX = -e.detail / 3; + } else { + this.deltaX = -e.deltaX / 40; } // Assume a vertical scroll if nothing else worked @@ -195,4 +199,4 @@ export class StandardWheelEvent { } } } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index ffef9180cc6..413a256483f 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -405,16 +405,16 @@ export class ActionBar extends Disposable implements IActionRunner { protected actionsList: HTMLElement; private _onDidBlur = this._register(new Emitter()); - get onDidBlur(): Event { return this._onDidBlur.event; } + readonly onDidBlur: Event = this._onDidBlur.event; private _onDidCancel = this._register(new Emitter()); - get onDidCancel(): Event { return this._onDidCancel.event; } + readonly onDidCancel: Event = this._onDidCancel.event; private _onDidRun = this._register(new Emitter()); - get onDidRun(): Event { return this._onDidRun.event; } + readonly onDidRun: Event = this._onDidRun.event; private _onDidBeforeRun = this._register(new Emitter()); - get onDidBeforeRun(): Event { return this._onDidBeforeRun.event; } + readonly onDidBeforeRun: Event = this._onDidBeforeRun.event; constructor(container: HTMLElement, options: IActionBarOptions = defaultOptions) { super(); diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index bdbce4e9e30..13e4b9c34be 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -57,7 +57,7 @@ export interface IBreadcrumbsItemEvent { export class BreadcrumbsWidget { - private readonly _disposables = new Array(); + private readonly _disposables = new DisposableStore(); private readonly _domNode: HTMLDivElement; private readonly _styleElement: HTMLStyleElement; private readonly _scrollable: DomScrollableElement; @@ -94,26 +94,25 @@ export class BreadcrumbsWidget { useShadows: false, scrollYToX: true }); - this._disposables.push(this._scrollable); - this._disposables.push(dom.addStandardDisposableListener(this._domNode, 'click', e => this._onClick(e))); + this._disposables.add(this._scrollable); + this._disposables.add(dom.addStandardDisposableListener(this._domNode, 'click', e => this._onClick(e))); container.appendChild(this._scrollable.getDomNode()); this._styleElement = dom.createStyleSheet(this._domNode); - let focusTracker = dom.trackFocus(this._domNode); - this._disposables.push(focusTracker); - this._disposables.push(focusTracker.onDidBlur(_ => this._onDidChangeFocus.fire(false))); - this._disposables.push(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true))); + const focusTracker = dom.trackFocus(this._domNode); + this._disposables.add(focusTracker); + this._disposables.add(focusTracker.onDidBlur(_ => this._onDidChangeFocus.fire(false))); + this._disposables.add(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true))); } dispose(): void { - dispose(this._disposables); + this._disposables.dispose(); dispose(this._pendingLayout); this._onDidSelectItem.dispose(); this._onDidFocusItem.dispose(); this._onDidChangeFocus.dispose(); this._domNode.remove(); - this._disposables.length = 0; this._nodes.length = 0; this._freeNodes.length = 0; } diff --git a/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts index ff349b87bd4..299b6534873 100644 --- a/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -6,7 +6,7 @@ import { SplitView, Orientation, ISplitViewStyles, IView as ISplitViewView } from 'vs/base/browser/ui/splitview/splitview'; import { $ } from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; -import { IView } from 'vs/base/browser/ui/grid/gridview'; +import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; @@ -68,6 +68,7 @@ export class CenteredViewLayout implements IDisposable { get maximumWidth(): number { return this.splitView ? this.splitView.maximumSize : this.view.maximumWidth; } get minimumHeight(): number { return this.view.minimumHeight; } get maximumHeight(): number { return this.view.maximumHeight; } + get onDidChange(): Event { return this.view.onDidChange; } layout(width: number, height: number): void { this.width = width; diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 21580062e5b..723f64dc4fa 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -22,10 +22,12 @@ export interface ICheckboxOpts extends ICheckboxStyles { export interface ICheckboxStyles { inputActiveOptionBorder?: Color; + inputActiveOptionBackground?: Color; } const defaultOpts = { - inputActiveOptionBorder: Color.fromHex('#007ACC') + inputActiveOptionBorder: Color.fromHex('#007ACC00'), + inputActiveOptionBackground: Color.fromHex('#0E639C50') }; export class CheckboxActionViewItem extends BaseActionViewItem { @@ -63,7 +65,7 @@ export class CheckboxActionViewItem extends BaseActionViewItem { } } - dipsose(): void { + dispose(): void { this.disposables.dispose(); super.dispose(); } @@ -72,10 +74,10 @@ export class CheckboxActionViewItem extends BaseActionViewItem { export class Checkbox extends Widget { private readonly _onChange = this._register(new Emitter()); - get onChange(): Event { return this._onChange.event; } + readonly onChange: Event = this._onChange.event; private readonly _onKeyDown = this._register(new Emitter()); - get onKeyDown(): Event { return this._onKeyDown.event; } + readonly onKeyDown: Event = this._onKeyDown.event; private readonly _opts: ICheckboxOpts; readonly domNode: HTMLElement; @@ -149,12 +151,16 @@ export class Checkbox extends Widget { if (styles.inputActiveOptionBorder) { this._opts.inputActiveOptionBorder = styles.inputActiveOptionBorder; } + if (styles.inputActiveOptionBackground) { + this._opts.inputActiveOptionBackground = styles.inputActiveOptionBackground; + } this.applyStyles(); } protected applyStyles(): void { if (this.domNode) { this.domNode.style.borderColor = this._checked && this._opts.inputActiveOptionBorder ? this._opts.inputActiveOptionBorder.toString() : 'transparent'; + this.domNode.style.backgroundColor = this._checked && this._opts.inputActiveOptionBackground ? this._opts.inputActiveOptionBackground.toString() : 'transparent'; } } diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 6dc7d9ee067..2e95c5955ac 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -15,7 +15,7 @@ import { ButtonGroup, IButtonStyles } from 'vs/base/browser/ui/button/button'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { isMacintosh } from 'vs/base/common/platform'; +import { isMacintosh, isLinux } from 'vs/base/common/platform'; export interface IDialogOptions { cancelId?: number; @@ -97,9 +97,17 @@ export class Dialog extends Disposable { clearNode(this.buttonsContainer); let focusedButton = 0; - this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true }); + const buttonGroup = this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true }); const buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId); - this.buttonGroup.buttons.forEach((button, index) => { + + // Set focused button to UI index + buttonMap.forEach((value, index) => { + if (value.index === 0) { + focusedButton = index; + } + }); + + buttonGroup.buttons.forEach((button, index) => { button.label = mnemonicButtonLabel(buttonMap[index].label, true); this._register(button.onDidClick(e => { @@ -115,18 +123,16 @@ export class Dialog extends Disposable { } let eventHandled = false; - if (this.buttonGroup) { - if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { - focusedButton = focusedButton + this.buttonGroup.buttons.length - 1; - focusedButton = focusedButton % this.buttonGroup.buttons.length; - this.buttonGroup.buttons[focusedButton].focus(); - eventHandled = true; - } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { - focusedButton++; - focusedButton = focusedButton % this.buttonGroup.buttons.length; - this.buttonGroup.buttons[focusedButton].focus(); - eventHandled = true; - } + if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { + focusedButton = focusedButton + buttonGroup.buttons.length - 1; + focusedButton = focusedButton % buttonGroup.buttons.length; + buttonGroup.buttons[focusedButton].focus(); + eventHandled = true; + } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { + focusedButton++; + focusedButton = focusedButton % buttonGroup.buttons.length; + buttonGroup.buttons[focusedButton].focus(); + eventHandled = true; } if (eventHandled) { @@ -192,7 +198,7 @@ export class Dialog extends Disposable { show(this.element); // Focus first element - this.buttonGroup.buttons[focusedButton].focus(); + buttonGroup.buttons[focusedButton].focus(); }); } @@ -243,7 +249,8 @@ export class Dialog extends Disposable { buttonMap.push({ label: button, index: index }); }); - if (isMacintosh) { + // macOS/linux: reverse button order + if (isMacintosh || isLinux) { if (cancelId !== undefined) { const cancelButton = buttonMap.splice(cancelId, 1)[0]; buttonMap.reverse(); diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index 38a5082b141..180e660f3a5 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -33,6 +33,7 @@ export interface IFindInputOptions extends IFindInputStyles { export interface IFindInputStyles extends IInputBoxStyles { inputActiveOptionBorder?: Color; + inputActiveOptionBackground?: Color; } const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input"); @@ -48,6 +49,7 @@ export class FindInput extends Widget { private fixFocusOnOptionClickEnabled = true; private inputActiveOptionBorder?: Color; + private inputActiveOptionBackground?: Color; private inputBackground?: Color; private inputForeground?: Color; private inputBorder?: Color; @@ -97,6 +99,7 @@ export class FindInput extends Widget { this.label = options.label || NLS_DEFAULT_LABEL; this.inputActiveOptionBorder = options.inputActiveOptionBorder; + this.inputActiveOptionBackground = options.inputActiveOptionBackground; this.inputBackground = options.inputBackground; this.inputForeground = options.inputForeground; this.inputBorder = options.inputBorder; @@ -173,6 +176,7 @@ export class FindInput extends Widget { public style(styles: IFindInputStyles): void { this.inputActiveOptionBorder = styles.inputActiveOptionBorder; + this.inputActiveOptionBackground = styles.inputActiveOptionBackground; this.inputBackground = styles.inputBackground; this.inputForeground = styles.inputForeground; this.inputBorder = styles.inputBorder; @@ -194,6 +198,7 @@ export class FindInput extends Widget { if (this.domNode) { const checkBoxStyles: ICheckboxStyles = { inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground, }; this.regex.style(checkBoxStyles); this.wholeWords.style(checkBoxStyles); @@ -294,7 +299,8 @@ export class FindInput extends Widget { this.regex = this._register(new RegexCheckbox({ appendTitle: appendRegexLabel, isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground })); this._register(this.regex.onChange(viaKeyboard => { this._onDidOptionChange.fire(viaKeyboard); @@ -310,7 +316,8 @@ export class FindInput extends Widget { this.wholeWords = this._register(new WholeWordsCheckbox({ appendTitle: appendWholeWordsLabel, isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground })); this._register(this.wholeWords.onChange(viaKeyboard => { this._onDidOptionChange.fire(viaKeyboard); @@ -323,7 +330,8 @@ export class FindInput extends Widget { this.caseSensitive = this._register(new CaseSensitiveCheckbox({ appendTitle: appendCaseSensitiveLabel, isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground })); this._register(this.caseSensitive.onChange(viaKeyboard => { this._onDidOptionChange.fire(viaKeyboard); diff --git a/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts index 62451f1a4b8..effef734a8c 100644 --- a/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts +++ b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts @@ -12,6 +12,7 @@ export interface IFindInputCheckboxOpts { readonly appendTitle: string; readonly isChecked: boolean; readonly inputActiveOptionBorder?: Color; + readonly inputActiveOptionBackground?: Color; } const NLS_CASE_SENSITIVE_CHECKBOX_LABEL = nls.localize('caseDescription', "Match Case"); @@ -24,7 +25,8 @@ export class CaseSensitiveCheckbox extends Checkbox { actionClassName: 'monaco-case-sensitive', title: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + opts.appendTitle, isChecked: opts.isChecked, - inputActiveOptionBorder: opts.inputActiveOptionBorder + inputActiveOptionBorder: opts.inputActiveOptionBorder, + inputActiveOptionBackground: opts.inputActiveOptionBackground }); } } @@ -35,7 +37,8 @@ export class WholeWordsCheckbox extends Checkbox { actionClassName: 'monaco-whole-word', title: NLS_WHOLE_WORD_CHECKBOX_LABEL + opts.appendTitle, isChecked: opts.isChecked, - inputActiveOptionBorder: opts.inputActiveOptionBorder + inputActiveOptionBorder: opts.inputActiveOptionBorder, + inputActiveOptionBackground: opts.inputActiveOptionBackground }); } } @@ -46,7 +49,8 @@ export class RegexCheckbox extends Checkbox { actionClassName: 'monaco-regex', title: NLS_REGEX_CHECKBOX_LABEL + opts.appendTitle, isChecked: opts.isChecked, - inputActiveOptionBorder: opts.inputActiveOptionBorder + inputActiveOptionBorder: opts.inputActiveOptionBorder, + inputActiveOptionBackground: opts.inputActiveOptionBackground }); } } diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 4178efc9e98..eb8476e1b8b 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -7,12 +7,11 @@ import 'vs/css!./gridview'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Disposable } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; -import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles } from './gridview'; -import { Event, Emitter } from 'vs/base/common/event'; -import { $ } from 'vs/base/browser/dom'; -import { LayoutPriority } from 'vs/base/browser/ui/splitview/splitview'; +import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, ILayoutController, LayoutController } from './gridview'; +import { Event } from 'vs/base/common/event'; +import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; -export { Orientation } from './gridview'; +export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview'; export const enum Direction { Up, @@ -30,9 +29,15 @@ function oppositeDirection(direction: Direction): Direction { } } +export interface IView extends IGridViewView { + readonly preferredHeight?: number; + readonly preferredWidth?: number; +} + export interface GridLeafNode { readonly view: T; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -117,10 +122,6 @@ function getDirectionOrientation(direction: Direction): Orientation { return direction === Direction.Up || direction === Direction.Down ? Orientation.VERTICAL : Orientation.HORIZONTAL; } -function getSize(dimensions: { width: number; height: number; }, orientation: Orientation) { - return orientation === Orientation.HORIZONTAL ? dimensions.width : dimensions.height; -} - export function getRelativeLocation(rootOrientation: Orientation, location: number[], direction: Direction): number[] { const orientation = getLocationOrientation(rootOrientation, location); const directionOrientation = getDirectionOrientation(direction); @@ -179,19 +180,27 @@ function getGridLocation(element: HTMLElement): number[] { return [...getGridLocation(ancestor), index]; } -export const enum Sizing { - Distribute = 'distribute', - Split = 'split' +export type DistributeSizing = { type: 'distribute' }; +export type SplitSizing = { type: 'split' }; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; + +export namespace Sizing { + export const Distribute: DistributeSizing = { type: 'distribute' }; + export const Split: SplitSizing = { type: 'split' }; + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export interface IGridStyles extends IGridViewStyles { } export interface IGridOptions { - styles?: IGridStyles; - proportionalLayout?: boolean; + readonly styles?: IGridStyles; + readonly proportionalLayout?: boolean; + readonly firstViewVisibleCachedSize?: number; + readonly layoutController?: ILayoutController; } -export class Grid extends Disposable { +export class Grid extends Disposable { protected gridview: GridView; private views = new Map(); @@ -209,16 +218,20 @@ export class Grid extends Disposable { get element(): HTMLElement { return this.gridview.element; } - sashResetSizing: Sizing = Sizing.Distribute; + private didLayout = false; constructor(view: T, options: IGridOptions = {}) { super(); this.gridview = new GridView(options); this._register(this.gridview); - this._register(this.gridview.onDidSashReset(this.doResetViewSize, this)); + this._register(this.gridview.onDidSashReset(this.onDidSashReset, this)); - this._addView(view, 0, [0]); + const size: number | GridViewSizing = typeof options.firstViewVisibleCachedSize === 'number' + ? GridViewSizing.Invisible(options.firstViewVisibleCachedSize) + : 0; + + this._addView(view, size, [0]); } style(styles: IGridStyles): void { @@ -227,6 +240,7 @@ export class Grid extends Disposable { layout(width: number, height: number): void { this.gridview.layout(width, height); + this.didLayout = true; } hasView(view: T): boolean { @@ -249,10 +263,12 @@ export class Grid extends Disposable { let viewSize: number | GridViewSizing; - if (size === Sizing.Split) { + if (typeof size === 'number') { + viewSize = size; + } else if (size.type === 'split') { const [, index] = tail(referenceLocation); viewSize = GridViewSizing.Split(index); - } else if (size === Sizing.Distribute) { + } else if (size.type === 'distribute') { viewSize = GridViewSizing.Distribute; } else { viewSize = size; @@ -272,7 +288,7 @@ export class Grid extends Disposable { } const location = this.getViewLocation(view); - this.gridview.removeView(location, sizing === Sizing.Distribute ? GridViewSizing.Distribute : undefined); + this.gridview.removeView(location, (sizing && sizing.type === 'distribute') ? GridViewSizing.Distribute : undefined); this.views.delete(view); } @@ -298,19 +314,12 @@ export class Grid extends Disposable { return this.gridview.swapViews(fromLocation, toLocation); } - resizeView(view: T, size: number): void { + resizeView(view: T, size: IViewSize): void { const location = this.getViewLocation(view); return this.gridview.resizeView(location, size); } - getViewSize(view: T): number { - const location = this.getViewLocation(view); - const viewSize = this.gridview.getViewSize(location); - return getLocationOrientation(this.orientation, location) === Orientation.HORIZONTAL ? viewSize.width : viewSize.height; - } - - // TODO@joao cleanup - getViewSize2(view: T): { width: number; height: number; } { + getViewSize(view: T): IViewSize { const location = this.getViewLocation(view); return this.gridview.getViewSize(location); } @@ -324,11 +333,25 @@ export class Grid extends Disposable { this.gridview.distributeViewSizes(); } + isViewVisible(view: T): boolean { + const location = this.getViewLocation(view); + return this.gridview.isViewVisible(location); + } + + setViewVisible(view: T, visible: boolean): void { + const location = this.getViewLocation(view); + this.gridview.setViewVisible(location, visible); + } + getViews(): GridBranchNode { - return this.gridview.getViews() as GridBranchNode; + return this.gridview.getView() as GridBranchNode; } getNeighborViews(view: T, direction: Direction, wrap: boolean = false): T[] { + if (!this.didLayout) { + throw new Error('Can\'t call getNeighborViews before first layout'); + } + const location = this.getViewLocation(view); const root = this.getViews(); const node = getGridNode(root, location); @@ -360,19 +383,37 @@ export class Grid extends Disposable { return getGridLocation(element); } - private doResetViewSize(location: number[]): void { - if (this.sashResetSizing === Sizing.Split) { - const orientation = getLocationOrientation(this.orientation, location); - const firstViewSize = getSize(this.gridview.getViewSize(location), orientation); - const [parentLocation, index] = tail(location); - const secondViewSize = getSize(this.gridview.getViewSize([...parentLocation, index + 1]), orientation); - const totalSize = firstViewSize + secondViewSize; - this.gridview.resizeView(location, Math.floor(totalSize / 2)); + private onDidSashReset(location: number[]): void { + const resizeToPreferredSize = (location: number[]): boolean => { + const node = this.gridview.getView(location) as GridNode; - } else { - const [parentLocation,] = tail(location); - this.gridview.distributeViewSizes(parentLocation); + if (isGridBranchNode(node)) { + return false; + } + + const direction = getLocationOrientation(this.orientation, location); + const size = direction === Orientation.HORIZONTAL ? node.view.preferredWidth : node.view.preferredHeight; + + if (typeof size !== 'number') { + return false; + } + + const viewSize = direction === Orientation.HORIZONTAL ? { width: Math.round(size) } : { height: Math.round(size) }; + this.gridview.resizeView(location, viewSize); + return true; + }; + + if (resizeToPreferredSize(location)) { + return; } + + const [parentLocation, index] = tail(location); + + if (resizeToPreferredSize([...parentLocation, index + 1])) { + return; + } + + this.gridview.distributeViewSizes(parentLocation); } } @@ -394,6 +435,7 @@ export interface ISerializedLeafNode { type: 'leaf'; data: object | null; size: number; + visible?: boolean; } export interface ISerializedBranchNode { @@ -417,6 +459,10 @@ export class SerializableGrid extends Grid { const size = orientation === Orientation.VERTICAL ? node.box.width : node.box.height; if (!isGridBranchNode(node)) { + if (typeof node.cachedVisibleSize === 'number') { + return { type: 'leaf', data: node.view.toJSON(), size: node.cachedVisibleSize, visible: false }; + } + return { type: 'leaf', data: node.view.toJSON(), size }; } @@ -441,25 +487,26 @@ export class SerializableGrid extends Grid { throw new Error('Invalid JSON: \'size\' property of node must be a number.'); } + const childSize = child.type === 'leaf' && child.visible === false ? 0 : child.size; const childBox: Box = orientation === Orientation.HORIZONTAL - ? { top: box.top, left: box.left + offset, width: child.size, height: box.height } - : { top: box.top + offset, left: box.left, width: box.width, height: child.size }; + ? { top: box.top, left: box.left + offset, width: childSize, height: box.height } + : { top: box.top + offset, left: box.left, width: box.width, height: childSize }; children.push(SerializableGrid.deserializeNode(child, orthogonal(orientation), childBox, deserializer)); - offset += child.size; + offset += childSize; } return { children, box }; } else if (json.type === 'leaf') { const view: T = deserializer.fromJSON(json.data); - return { view, box }; + return { view, box, cachedVisibleSize: json.visible === false ? json.size : undefined }; } throw new Error('Invalid JSON: \'type\' property must be either \'branch\' or \'leaf\'.'); } - private static getFirstLeaf(node: GridNode): GridLeafNode | undefined { + private static getFirstLeaf(node: GridNode): GridLeafNode { if (!isGridBranchNode(node)) { return node; } @@ -488,11 +535,19 @@ export class SerializableGrid extends Grid { throw new Error('Invalid serialized state, first leaf not found'); } + const layoutController = new LayoutController(false); + options = { ...options, layoutController }; + + if (typeof firstLeaf.cachedVisibleSize === 'number') { + options = { ...options, firstViewVisibleCachedSize: firstLeaf.cachedVisibleSize }; + } + const result = new SerializableGrid(firstLeaf.view, options); result.orientation = orientation; result.restoreViews(firstLeaf.view, orientation, root); result.initialLayoutContext = { width, height, root }; + layoutController.isLayoutEnabled = true; return result; } @@ -537,13 +592,16 @@ export class SerializableGrid extends Grid { const firstLeaves = node.children.map(c => SerializableGrid.getFirstLeaf(c)); for (let i = 1; i < firstLeaves.length; i++) { - const size = orientation === Orientation.VERTICAL ? firstLeaves[i]!.box.height : firstLeaves[i]!.box.width; - this.addView(firstLeaves[i]!.view, size, referenceView, direction); - referenceView = firstLeaves[i]!.view; + const node = firstLeaves[i]; + const size: number | InvisibleSizing = typeof node.cachedVisibleSize === 'number' + ? GridViewSizing.Invisible(node.cachedVisibleSize) + : (orientation === Orientation.VERTICAL ? node.box.height : node.box.width); + this.addView(node.view, size, referenceView, direction); + referenceView = node.view; } for (let i = 0; i < node.children.length; i++) { - this.restoreViews(firstLeaves[i]!.view, orthogonal(orientation), node.children[i]); + this.restoreViews(firstLeaves[i].view, orthogonal(orientation), node.children[i]); } } @@ -563,8 +621,11 @@ export class SerializableGrid extends Grid { const childLocation = [...location, i]; if (i < node.children.length - 1) { - const size = orientation === Orientation.VERTICAL ? child.box.height : child.box.width; - this.gridview.resizeView(childLocation, Math.floor(size * scale)); + const size = orientation === Orientation.VERTICAL + ? { height: Math.floor(child.box.height * scale) } + : { width: Math.floor(child.box.width * scale) }; + + this.gridview.resizeView(childLocation, size); } this.restoreViewsSize(childLocation, child, orthogonal(orientation), widthScale, heightScale); @@ -648,63 +709,3 @@ export function createSerializedGrid(gridDescriptor: GridDescriptor): ISerialize height: height || 1 }; } - -export class View implements IView { - - readonly element = $('.grid-view-view'); - - private visible = false; - private width: number | undefined; - private height: number | undefined; - private orientation: Orientation = Orientation.HORIZONTAL; - - get minimumWidth(): number { return this.visible ? this.view.minimumWidth : 0; } - get maximumWidth(): number { return this.visible ? this.view.maximumWidth : (this.orientation === Orientation.HORIZONTAL ? 0 : Number.POSITIVE_INFINITY); } - get minimumHeight(): number { return this.visible ? this.view.minimumHeight : 0; } - get maximumHeight(): number { return this.visible ? this.view.maximumHeight : (this.orientation === Orientation.VERTICAL ? 0 : Number.POSITIVE_INFINITY); } - - private onDidChangeVisibility = new Emitter<{ width: number; height: number; } | undefined>(); - readonly onDidChange: Event<{ width: number; height: number; } | undefined>; - - get priority(): LayoutPriority | undefined { return this.view.priority; } - get snapSize(): number | undefined { return this.visible ? this.view.snapSize : undefined; } - - constructor(private view: IView) { - this.show(); - this.onDidChange = Event.any(this.onDidChangeVisibility.event, Event.filter(view.onDidChange, () => this.visible)); - } - - show(): void { - if (this.visible) { - return; - } - - this.visible = true; - - this.element.appendChild(this.view.element); - this.onDidChangeVisibility.fire(typeof this.width === 'number' ? { width: this.width, height: this.height! } : undefined); - } - - hide(): void { - if (!this.visible) { - return; - } - - this.visible = false; - - this.element.removeChild(this.view.element); - this.onDidChangeVisibility.fire(undefined); - } - - layout(width: number, height: number, orientation: Orientation): void { - this.orientation = orientation; - - if (!this.visible) { - return; - } - - this.view.layout(width, height, orientation); - this.width = width; - this.height = height; - } -} \ No newline at end of file diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index e4e6f8909ad..81a6950a65b 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -15,16 +15,22 @@ import { Color } from 'vs/base/common/color'; export { Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview'; export { Orientation } from 'vs/base/browser/ui/sash/sash'; +export interface IViewSize { + readonly width: number; + readonly height: number; +} + export interface IView { readonly element: HTMLElement; readonly minimumWidth: number; readonly maximumWidth: number; readonly minimumHeight: number; readonly maximumHeight: number; - readonly onDidChange: Event<{ width: number; height: number; } | undefined>; + readonly onDidChange: Event; readonly priority?: LayoutPriority; - readonly snapSize?: number; + readonly snap?: boolean; layout(width: number, height: number, orientation: Orientation): void; + setVisible?(visible: boolean): void; } export function orthogonal(orientation: Orientation): Orientation { @@ -41,6 +47,7 @@ export interface Box { export interface GridLeafNode { readonly view: IView; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -60,9 +67,18 @@ const defaultStyles: IGridViewStyles = { separatorBorder: Color.transparent }; +export interface ILayoutController { + readonly isLayoutEnabled: boolean; +} + +export class LayoutController implements ILayoutController { + constructor(public isLayoutEnabled: boolean) { } +} + export interface IGridViewOptions { - styles?: IGridViewStyles; - proportionalLayout?: boolean; // default true + readonly styles?: IGridViewStyles; + readonly proportionalLayout?: boolean; // default true + readonly layoutController?: ILayoutController; } class BranchNode implements ISplitView, IDisposable { @@ -96,6 +112,22 @@ class BranchNode implements ISplitView, IDisposable { return Math.min(...this.children.map(c => c.maximumOrthogonalSize)); } + get priority(): LayoutPriority { + if (this.children.length === 0) { + return LayoutPriority.Normal; + } + + const priorities = this.children.map(c => typeof c.priority === 'undefined' ? LayoutPriority.Normal : c.priority); + + if (priorities.some(p => p === LayoutPriority.High)) { + return LayoutPriority.High; + } else if (priorities.some(p => p === LayoutPriority.Low)) { + return LayoutPriority.Low; + } + + return LayoutPriority.Normal; + } + get minimumOrthogonalSize(): number { return this.splitview.minimumSize; } @@ -173,6 +205,12 @@ class BranchNode implements ISplitView, IDisposable { } } + setVisible(visible: boolean): void { + for (const child of this.children) { + child.setVisible(visible); + } + } + orthogonalLayout(size: number): void { this._size = size; this.splitview.layout(size); @@ -299,6 +337,30 @@ class BranchNode implements ISplitView, IDisposable { return this.splitview.getViewSize(index); } + isChildVisible(index: number): boolean { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + return this.splitview.isViewVisible(index); + } + + setChildVisible(index: number, visible: boolean): void { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + this.splitview.setViewVisible(index, visible); + } + + getChildCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + return this.splitview.getViewCachedVisibleSize(index); + } + private onDidChildrenChange(): void { const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); this.childrenChangeDisposable.dispose(); @@ -380,6 +442,9 @@ class LeafNode implements ISplitView, IDisposable { private _size: number = 0; get size(): number { return this._size; } + private _cachedVisibleSize: number | undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } + private _orthogonalSize: number; get orthogonalSize(): number { return this._orthogonalSize; } @@ -410,7 +475,8 @@ class LeafNode implements ISplitView, IDisposable { constructor( readonly view: IView, readonly orientation: Orientation, - orthogonalSize: number = 0 + readonly layoutController: ILayoutController, + orthogonalSize: number ) { this._orthogonalSize = orthogonalSize; @@ -458,8 +524,8 @@ class LeafNode implements ISplitView, IDisposable { return this.view.priority; } - get snapSize(): number | undefined { - return this.view.snapSize; + get snap(): boolean | undefined { + return this.view.snap; } get minimumOrthogonalSize(): number { @@ -480,12 +546,30 @@ class LeafNode implements ISplitView, IDisposable { layout(size: number): void { this._size = size; - return this.view.layout(this.width, this.height, orthogonal(this.orientation)); + + if (this.layoutController.isLayoutEnabled) { + this.view.layout(this.width, this.height, orthogonal(this.orientation)); + } + } + + setVisible(visible: boolean): void { + if (visible) { + this._cachedVisibleSize = undefined; + } else { + this._cachedVisibleSize = this._size; + } + + if (this.view.setVisible) { + this.view.setVisible(visible); + } } orthogonalLayout(size: number): void { this._orthogonalSize = size; - return this.view.layout(this.width, this.height, orthogonal(this.orientation)); + + if (this.layoutController.isLayoutEnabled) { + this.view.layout(this.width, this.height, orthogonal(this.orientation)); + } } dispose(): void { } @@ -516,7 +600,7 @@ function flipNode(node: T, size: number, orthogonalSize: number) return result as T; } else { - return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), orthogonalSize) as T; + return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), (node as LeafNode).layoutController, orthogonalSize) as T; } } @@ -573,14 +657,17 @@ export class GridView implements IDisposable { get maximumWidth(): number { return this.root.maximumHeight; } get maximumHeight(): number { return this.root.maximumHeight; } - private _onDidChange = new Relay<{ width: number; height: number; } | undefined>(); + private _onDidChange = new Relay(); readonly onDidChange = this._onDidChange.event; + private layoutController: LayoutController; + constructor(options: IGridViewOptions = {}) { this.element = $('.monaco-grid-view'); this.styles = options.styles || defaultStyles; this.proportionalLayout = typeof options.proportionalLayout !== 'undefined' ? !!options.proportionalLayout : true; this.root = new BranchNode(Orientation.VERTICAL, this.styles, this.proportionalLayout); + this.layoutController = options.layoutController || new LayoutController(true); } style(styles: IGridViewStyles): void { @@ -602,26 +689,34 @@ export class GridView implements IDisposable { const [pathToParent, parent] = this.getNode(rest); if (parent instanceof BranchNode) { - const node = new LeafNode(view, orthogonal(parent.orientation), parent.orthogonalSize); + const node = new LeafNode(view, orthogonal(parent.orientation), this.layoutController, parent.orthogonalSize); parent.addChild(node, size, index); } else { const [, grandParent] = tail(pathToParent); const [, parentIndex] = tail(rest); + + let newSiblingSize: number | Sizing = 0; + + const newSiblingCachedVisibleSize = grandParent.getChildCachedVisibleSize(parentIndex); + if (typeof newSiblingCachedVisibleSize === 'number') { + newSiblingSize = Sizing.Invisible(newSiblingCachedVisibleSize); + } + grandParent.removeChild(parentIndex); const newParent = new BranchNode(parent.orientation, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize); grandParent.addChild(newParent, parent.size, parentIndex); newParent.orthogonalLayout(parent.orthogonalSize); - const newSibling = new LeafNode(parent.view, grandParent.orientation, parent.size); - newParent.addChild(newSibling, 0, 0); + const newSibling = new LeafNode(parent.view, grandParent.orientation, this.layoutController, parent.size); + newParent.addChild(newSibling, newSiblingSize, 0); if (typeof size !== 'number' && size.type === 'split') { size = Sizing.Split(0); } - const node = new LeafNode(view, grandParent.orientation, parent.size); + const node = new LeafNode(view, grandParent.orientation, this.layoutController, parent.size); newParent.addChild(node, size, index); } } @@ -683,7 +778,7 @@ export class GridView implements IDisposable { grandParent.addChild(child, child.size, parentIndex + i); } } else { - const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), sibling.size); + const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), this.layoutController, sibling.size); grandParent.addChild(newSibling, sibling.orthogonalSize, parentIndex); } @@ -747,18 +842,33 @@ export class GridView implements IDisposable { } } - resizeView(location: number[], size: number): void { + resizeView(location: number[], { width, height }: Partial): void { const [rest, index] = tail(location); - const [, parent] = this.getNode(rest); + const [pathToParent, parent] = this.getNode(rest); if (!(parent instanceof BranchNode)) { throw new Error('Invalid location'); } - parent.resizeChild(index, size); + if (!width && !height) { + return; + } + + const [parentSize, grandParentSize] = parent.orientation === Orientation.HORIZONTAL ? [width, height] : [height, width]; + + if (typeof grandParentSize === 'number' && pathToParent.length > 0) { + const [, grandParent] = tail(pathToParent); + const [, parentIndex] = tail(rest); + + grandParent.resizeChild(parentIndex, grandParentSize); + } + + if (typeof parentSize === 'number') { + parent.resizeChild(index, parentSize); + } } - getViewSize(location: number[]): { width: number; height: number; } { + getViewSize(location: number[]): IViewSize { const [, node] = this.getNode(location); return { width: node.width, height: node.height }; } @@ -790,13 +900,38 @@ export class GridView implements IDisposable { node.distributeViewSizes(); } - getViews(): GridBranchNode { - return this._getViews(this.root, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }) as GridBranchNode; + isViewVisible(location: number[]): boolean { + const [rest, index] = tail(location); + const [, parent] = this.getNode(rest); + + if (!(parent instanceof BranchNode)) { + throw new Error('Invalid from location'); + } + + return parent.isChildVisible(index); + } + + setViewVisible(location: number[], visible: boolean): void { + const [rest, index] = tail(location); + const [, parent] = this.getNode(rest); + + if (!(parent instanceof BranchNode)) { + throw new Error('Invalid from location'); + } + + parent.setChildVisible(index, visible); + } + + getView(): GridBranchNode; + getView(location?: number[]): GridNode; + getView(location?: number[]): GridNode { + const node = location ? this.getNode(location)[1] : this._root; + return this._getViews(node, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }); } private _getViews(node: Node, orientation: Orientation, box: Box): GridNode { if (node instanceof LeafNode) { - return { view: node.view, box }; + return { view: node.view, box, cachedVisibleSize: node.cachedVisibleSize }; } const children: GridNode[] = []; diff --git a/src/vs/base/browser/ui/list/list.css b/src/vs/base/browser/ui/list/list.css index 3aa2e653473..1c1fa4c8223 100644 --- a/src/vs/base/browser/ui/list/list.css +++ b/src/vs/base/browser/ui/list/list.css @@ -126,13 +126,13 @@ -webkit-appearance: none; width: 16px; height: 16px; - background: url("media/no-filter.svg"); + background: url("media/no-filter-light.svg"); background-position: 50% 50%; cursor: pointer; } .monaco-list-type-filter > .controls > .filter:checked { - background-image: url("media/filter.svg"); + background-image: url("media/filter-light.svg"); } .vs-dark .monaco-list-type-filter > .controls > .filter { @@ -153,7 +153,7 @@ .monaco-list-type-filter > .controls > .clear { border: none; - background: url("media/close.svg"); + background: url("media/close-light.svg"); cursor: pointer; } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 0e0a4df34bc..6b920ee1e7a 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -111,7 +111,7 @@ class Trait implements ISpliceable, IDisposable { private sortedIndexes: number[] = []; private _onChange = new Emitter(); - get onChange(): Event { return this._onChange.event; } + readonly onChange: Event = this._onChange.event; get trait(): string { return this._trait; } @@ -236,7 +236,7 @@ class KeyboardController implements IDisposable { private view: ListView, options: IListOptions ) { - const multipleSelectionSupport = !(options.multipleSelectionSupport === false); + const multipleSelectionSupport = options.multipleSelectionSupport !== false; this.openController = options.openController || DefaultOpenController; @@ -329,6 +329,7 @@ export function mightProducePrintableCharacter(event: IKeyboardEvent): boolean { return (event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z) || (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9) + || (event.keyCode >= KeyCode.NUMPAD_0 && event.keyCode <= KeyCode.NUMPAD_9) || (event.keyCode >= KeyCode.US_SEMICOLON && event.keyCode <= KeyCode.US_QUOTE); } @@ -1164,7 +1165,7 @@ export class List implements ISpliceable, IDisposable { readonly onDidBlur: Event; private _onDidDispose = new Emitter(); - get onDidDispose(): Event { return this._onDidDispose.event; } + readonly onDidDispose: Event = this._onDidDispose.event; constructor( container: HTMLElement, diff --git a/src/vs/base/browser/ui/list/media/close-dark.svg b/src/vs/base/browser/ui/list/media/close-dark.svg index 751e89b3b02..7305a8f099a 100644 --- a/src/vs/base/browser/ui/list/media/close-dark.svg +++ b/src/vs/base/browser/ui/list/media/close-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/list/media/close-hc.svg b/src/vs/base/browser/ui/list/media/close-hc.svg index c20895c60aa..7305a8f099a 100644 --- a/src/vs/base/browser/ui/list/media/close-hc.svg +++ b/src/vs/base/browser/ui/list/media/close-hc.svg @@ -1,33 +1,3 @@ - - - - - - image/svg+xml - - - - - - - + + diff --git a/src/vs/base/browser/ui/list/media/close-light.svg b/src/vs/base/browser/ui/list/media/close-light.svg new file mode 100644 index 00000000000..ecddcd665b5 --- /dev/null +++ b/src/vs/base/browser/ui/list/media/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/list/media/close.svg b/src/vs/base/browser/ui/list/media/close.svg deleted file mode 100644 index fde34404d4e..00000000000 --- a/src/vs/base/browser/ui/list/media/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/list/media/filter-dark.svg b/src/vs/base/browser/ui/list/media/filter-dark.svg index 0925909a117..46c35f4374d 100644 --- a/src/vs/base/browser/ui/list/media/filter-dark.svg +++ b/src/vs/base/browser/ui/list/media/filter-dark.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/filter-hc.svg b/src/vs/base/browser/ui/list/media/filter-hc.svg index 0e2724f52e2..d7b6bdd3923 100644 --- a/src/vs/base/browser/ui/list/media/filter-hc.svg +++ b/src/vs/base/browser/ui/list/media/filter-hc.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/filter-light.svg b/src/vs/base/browser/ui/list/media/filter-light.svg new file mode 100644 index 00000000000..2550d80cb70 --- /dev/null +++ b/src/vs/base/browser/ui/list/media/filter-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/list/media/filter.svg b/src/vs/base/browser/ui/list/media/filter.svg deleted file mode 100644 index f8c011064b1..00000000000 --- a/src/vs/base/browser/ui/list/media/filter.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/base/browser/ui/list/media/no-filter-dark.svg b/src/vs/base/browser/ui/list/media/no-filter-dark.svg index 5f495c006dc..6fc07d81a55 100644 --- a/src/vs/base/browser/ui/list/media/no-filter-dark.svg +++ b/src/vs/base/browser/ui/list/media/no-filter-dark.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/no-filter-hc.svg b/src/vs/base/browser/ui/list/media/no-filter-hc.svg index 31d8f70f05a..6fc07d81a55 100644 --- a/src/vs/base/browser/ui/list/media/no-filter-hc.svg +++ b/src/vs/base/browser/ui/list/media/no-filter-hc.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/no-filter-light.svg b/src/vs/base/browser/ui/list/media/no-filter-light.svg new file mode 100644 index 00000000000..3608b15d29e --- /dev/null +++ b/src/vs/base/browser/ui/list/media/no-filter-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/list/media/no-filter.svg b/src/vs/base/browser/ui/list/media/no-filter.svg deleted file mode 100644 index 760cc3c4403..00000000000 --- a/src/vs/base/browser/ui/list/media/no-filter.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/base/browser/ui/list/rangeMap.ts b/src/vs/base/browser/ui/list/rangeMap.ts index 73c6b7419ed..1bf7217d0af 100644 --- a/src/vs/base/browser/ui/list/rangeMap.ts +++ b/src/vs/base/browser/ui/list/rangeMap.ts @@ -190,4 +190,4 @@ export class RangeMap { dispose() { this.groups = null!; // StrictNullOverride: nulling out ok in dispose } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/menu/check.svg b/src/vs/base/browser/ui/menu/check.svg index 3f365c4800e..865cc83c347 100644 --- a/src/vs/base/browser/ui/menu/check.svg +++ b/src/vs/base/browser/ui/menu/check.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/menu/ellipsis.svg b/src/vs/base/browser/ui/menu/ellipsis.svg index e3f85623356..2c52e359f61 100644 --- a/src/vs/base/browser/ui/menu/ellipsis.svg +++ b/src/vs/base/browser/ui/menu/ellipsis.svg @@ -1 +1,5 @@ -Ellipsis_bold_16x \ No newline at end of file + + + + + diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 3e0efee82c9..874bc9482e1 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -212,7 +212,13 @@ export class Sash extends Disposable { return; } - const iframes = getElementsByTagName('iframe'); + // Select both iframes and webviews; internally Electron nests an iframe + // in its component, but this isn't queryable. + const iframes = [ + ...getElementsByTagName('iframe'), + ...getElementsByTagName('webview'), + ]; + for (const iframe of iframes) { iframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash } @@ -254,7 +260,7 @@ export class Sash extends Disposable { style.innerHTML = `* { cursor: ${cursor} !important; }`; }; - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); updateStyle(); @@ -278,9 +284,8 @@ export class Sash extends Disposable { removeClass(this.el, 'active'); this._onDidEnd.fire(); - dispose(disposables); + disposables.dispose(); - const iframes = getElementsByTagName('iframe'); for (const iframe of iframes) { iframe.style.pointerEvents = 'auto'; } diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index fbf8d5dcd13..1c1ded9eb2c 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/scrollbars'; +import { isEdgeOrIE } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -312,7 +313,7 @@ export abstract class AbstractScrollableElement extends Widget { this._onMouseWheel(new StandardWheelEvent(browserEvent)); }; - this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, 'mousewheel', onMouseWheel)); + this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel)); } } diff --git a/src/vs/base/browser/ui/splitview/splitview.css b/src/vs/base/browser/ui/splitview/splitview.css index 7479f5178d7..6fb8f1c61d0 100644 --- a/src/vs/base/browser/ui/splitview/splitview.css +++ b/src/vs/base/browser/ui/splitview/splitview.css @@ -41,6 +41,10 @@ position: relative; } +.monaco-split-view2 > .split-view-container > .split-view-view:not(.visible) { + display: none; +} + .monaco-split-view2.vertical > .split-view-container > .split-view-view { width: 100%; } diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index fc104cc5543..6f031dac570 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -47,7 +47,9 @@ export interface IView { readonly maximumSize: number; readonly onDidChange: Event; readonly priority?: LayoutPriority; + readonly snap?: boolean; layout(size: number, orientation: Orientation): void; + setVisible?(visible: boolean): void; } interface ISashEvent { @@ -57,12 +59,98 @@ interface ISashEvent { alt: boolean; } -interface IViewItem { - view: IView; - size: number; - container: HTMLElement; - disposable: IDisposable; - layout(): void; +type ViewItemSize = number | { cachedVisibleSize: number }; + +abstract class ViewItem { + + private _size: number; + set size(size: number) { + this._size = size; + } + + get size(): number { + return this._size; + } + + private _cachedVisibleSize: number | undefined = undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } + + get visible(): boolean { + return typeof this._cachedVisibleSize === 'undefined'; + } + + set visible(visible: boolean) { + if (visible === this.visible) { + return; + } + + if (visible) { + this.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize); + this._cachedVisibleSize = undefined; + } else { + this._cachedVisibleSize = this.size; + this.size = 0; + } + + dom.toggleClass(this.container, 'visible', visible); + + if (this.view.setVisible) { + this.view.setVisible(visible); + } + } + + get minimumSize(): number { return this.visible ? this.view.minimumSize : 0; } + get viewMinimumSize(): number { return this.view.minimumSize; } + + get maximumSize(): number { return this.visible ? this.view.maximumSize : 0; } + get viewMaximumSize(): number { return this.view.maximumSize; } + + get priority(): LayoutPriority | undefined { return this.view.priority; } + get snap(): boolean { return !!this.view.snap; } + + constructor( + protected container: HTMLElement, + private view: IView, + size: ViewItemSize, + private disposable: IDisposable + ) { + if (typeof size === 'number') { + this._size = size; + this._cachedVisibleSize = undefined; + } else { + this._size = 0; + this._cachedVisibleSize = size.cachedVisibleSize; + } + + dom.addClass(container, 'visible'); + } + + abstract layout(): void; + + layoutView(orientation: Orientation): void { + this.view.layout(this.size, orientation); + } + + dispose(): IView { + this.disposable.dispose(); + return this.view; + } +} + +class VerticalViewItem extends ViewItem { + + layout(): void { + this.container.style.height = `${this.size}px`; + this.layoutView(Orientation.VERTICAL); + } +} + +class HorizontalViewItem extends ViewItem { + + layout(): void { + this.container.style.width = `${this.size}px`; + this.layoutView(Orientation.HORIZONTAL); + } } interface ISashItem { @@ -70,6 +158,11 @@ interface ISashItem { disposable: IDisposable; } +interface ISashDragSnapState { + readonly index: number; + readonly limitDelta: number; +} + interface ISashDragState { index: number; start: number; @@ -78,6 +171,8 @@ interface ISashDragState { minDelta: number; maxDelta: number; alt: boolean; + snapBefore: ISashDragSnapState | undefined; + snapAfter: ISashDragSnapState | undefined; disposable: IDisposable; } @@ -88,11 +183,13 @@ enum State { export type DistributeSizing = { type: 'distribute' }; export type SplitSizing = { type: 'split', index: number }; -export type Sizing = DistributeSizing | SplitSizing; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; export namespace Sizing { export const Distribute: DistributeSizing = { type: 'distribute' }; export function Split(index: number): SplitSizing { return { type: 'split', index }; } + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export class SplitView extends Disposable { @@ -104,7 +201,7 @@ export class SplitView extends Disposable { private size = 0; private contentSize = 0; private proportions: undefined | number[] = undefined; - private viewItems: IViewItem[] = []; + private viewItems: ViewItem[] = []; private sashItems: ISashItem[] = []; private sashDragState: ISashDragState; private state: State = State.Idle; @@ -122,11 +219,11 @@ export class SplitView extends Disposable { } get minimumSize(): number { - return this.viewItems.reduce((r, item) => r + item.view.minimumSize, 0); + return this.viewItems.reduce((r, item) => r + item.minimumSize, 0); } get maximumSize(): number { - return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.view.maximumSize, 0); + return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0); } private _orthogonalStartSash: Sash | undefined; @@ -201,26 +298,22 @@ export class SplitView extends Disposable { const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container)); const disposable = combinedDisposable(onChangeDisposable, containerDisposable); - const layoutContainer = this.orientation === Orientation.VERTICAL - ? () => item.container.style.height = `${item.size}px` - : () => item.container.style.width = `${item.size}px`; - - const layout = () => { - layoutContainer(); - item.view.layout(item.size, this.orientation); - }; - - let viewSize: number; + let viewSize: ViewItemSize; if (typeof size === 'number') { viewSize = size; } else if (size.type === 'split') { viewSize = this.getViewSize(size.index) / 2; + } else if (size.type === 'invisible') { + viewSize = { cachedVisibleSize: size.cachedVisibleSize }; } else { viewSize = view.minimumSize; } - const item: IViewItem = { view, container, size: viewSize, layout, disposable }; + const item = this.orientation === Orientation.VERTICAL + ? new VerticalViewItem(container, view, viewSize, disposable) + : new HorizontalViewItem(container, view, viewSize, disposable); + this.viewItems.splice(index, 0, item); // Add sash @@ -243,7 +336,24 @@ export class SplitView extends Disposable { const onChangeDisposable = onChange(this.onSashChange, this); const onEnd = Event.map(sash.onDidEnd, () => firstIndex(this.sashItems, item => item.sash === sash)); const onEndDisposable = onEnd(this.onSashEnd, this); - const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); + + const onDidResetDisposable = sash.onDidReset(() => { + const index = firstIndex(this.sashItems, item => item.sash === sash); + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) { + return; + } + + if (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) { + return; + } + + this._onDidSashReset.fire(index); + }); const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); const sashItem: ISashItem = { sash, disposable }; @@ -253,13 +363,13 @@ export class SplitView extends Disposable { container.appendChild(view.element); - let highPriorityIndex: number | undefined; + let highPriorityIndexes: number[] | undefined; if (typeof size !== 'number' && size.type === 'split') { - highPriorityIndex = size.index; + highPriorityIndexes = [size.index]; } - this.relayout(index, highPriorityIndex); + this.relayout([index], highPriorityIndexes); this.state = State.Idle; if (typeof size !== 'number' && size.type === 'distribute') { @@ -280,7 +390,7 @@ export class SplitView extends Disposable { // Remove view const viewItem = this.viewItems.splice(index, 1)[0]; - viewItem.disposable.dispose(); + const view = viewItem.dispose(); // Remove sash if (this.viewItems.length >= 1) { @@ -296,7 +406,7 @@ export class SplitView extends Disposable { this.distributeViewSizes(); } - return viewItem.view; + return view; } moveView(from: number, to: number): void { @@ -327,15 +437,34 @@ export class SplitView extends Disposable { this.addView(fromView, toSize, to); } - private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void { - const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); - const lowPriorityIndexes = typeof lowPriorityIndex === 'number' ? [lowPriorityIndex] : undefined; - const highPriorityIndexes = typeof highPriorityIndex === 'number' ? [highPriorityIndex] : undefined; + isViewVisible(index: number): boolean { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } - this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes); - this.distributeEmptySpace(); + const viewItem = this.viewItems[index]; + return viewItem.visible; + } + + setViewVisible(index: number, visible: boolean): void { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } + + const viewItem = this.viewItems[index]; + viewItem.visible = visible; + + this.distributeEmptySpace(index); this.layoutViews(); - this.saveProportions(); + } + + getViewCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } + + const viewItem = this.viewItems[index]; + return viewItem.cachedVisibleSize; } layout(size: number): void { @@ -344,14 +473,14 @@ export class SplitView extends Disposable { if (!this.proportions) { const indexes = range(this.viewItems.length); - const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.Low); - const highPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.High); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes); } else { for (let i = 0; i < this.viewItems.length; i++) { const item = this.viewItems[i]; - item.size = clamp(Math.round(this.proportions[i] * size), item.view.minimumSize, item.view.maximumSize); + item.size = clamp(Math.round(this.proportions[i] * size), item.minimumSize, item.maximumSize); } } @@ -391,35 +520,71 @@ export class SplitView extends Disposable { if (isLastSash) { const viewItem = this.viewItems[index]; - minDelta = (viewItem.view.minimumSize - viewItem.size) / 2; - maxDelta = (viewItem.view.maximumSize - viewItem.size) / 2; + minDelta = (viewItem.minimumSize - viewItem.size) / 2; + maxDelta = (viewItem.maximumSize - viewItem.size) / 2; } else { const viewItem = this.viewItems[index + 1]; - minDelta = (viewItem.size - viewItem.view.maximumSize) / 2; - maxDelta = (viewItem.size - viewItem.view.minimumSize) / 2; + minDelta = (viewItem.size - viewItem.maximumSize) / 2; + maxDelta = (viewItem.size - viewItem.minimumSize) / 2; } } - this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, disposable }; + let snapBefore: ISashDragSnapState | undefined; + let snapAfter: ISashDragSnapState | undefined; + + if (!alt) { + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0); + const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].viewMaximumSize - sizes[i]), 0); + const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0); + const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].viewMaximumSize), 0); + const minDelta = Math.max(minDeltaUp, minDeltaDown); + const maxDelta = Math.min(maxDeltaDown, maxDeltaUp); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number') { + const viewItem = this.viewItems[snapBeforeIndex]; + const halfSize = Math.floor(viewItem.viewMinimumSize / 2); + + snapBefore = { + index: snapBeforeIndex, + limitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize + }; + } + + if (typeof snapAfterIndex === 'number') { + const viewItem = this.viewItems[snapAfterIndex]; + const halfSize = Math.floor(viewItem.viewMinimumSize / 2); + + snapAfter = { + index: snapAfterIndex, + limitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize + }; + } + } + + this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapBefore, snapAfter, disposable }; }; resetSashDragState(start, alt); } private onSashChange({ current }: ISashEvent): void { - const { index, start, sizes, alt, minDelta, maxDelta } = this.sashDragState; + const { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState; this.sashDragState.current = current; const delta = current - start; - const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta); + const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter); if (alt) { const isLastSash = index === this.sashItems.length - 1; const newSizes = this.viewItems.map(i => i.size); const viewItemIndex = isLastSash ? index : index + 1; const viewItem = this.viewItems[viewItemIndex]; - const newMinDelta = viewItem.size - viewItem.view.maximumSize; - const newMaxDelta = viewItem.size - viewItem.view.minimumSize; + const newMinDelta = viewItem.size - viewItem.maximumSize; + const newMaxDelta = viewItem.size - viewItem.minimumSize; const resizeIndex = isLastSash ? index - 1 : index + 1; this.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta); @@ -435,7 +600,7 @@ export class SplitView extends Disposable { this.saveProportions(); } - private onViewChange(item: IViewItem, size: number | undefined): void { + private onViewChange(item: ViewItem, size: number | undefined): void { const index = this.viewItems.indexOf(item); if (index < 0 || index >= this.viewItems.length) { @@ -443,7 +608,7 @@ export class SplitView extends Disposable { } size = typeof size === 'number' ? size : item.size; - size = clamp(size, item.view.minimumSize, item.view.maximumSize); + size = clamp(size, item.minimumSize, item.maximumSize); if (this.inverseAltBehavior && index > 0) { // In this case, we want the view to grow or shrink both sides equally @@ -453,7 +618,7 @@ export class SplitView extends Disposable { this.layoutViews(); } else { item.size = size; - this.relayout(index, undefined); + this.relayout([index], undefined); } } @@ -468,42 +633,41 @@ export class SplitView extends Disposable { return; } + const indexes = range(this.viewItems.length).filter(i => i !== index); + const lowPriorityIndexes = [...indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low), index]; + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); + const item = this.viewItems[index]; size = Math.round(size); - size = clamp(size, item.view.minimumSize, item.view.maximumSize); - let delta = size - item.size; + size = clamp(size, item.minimumSize, Math.min(item.maximumSize, this.size)); - if (delta !== 0 && index < this.viewItems.length - 1) { - const downIndexes = range(index + 1, this.viewItems.length); - const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0); - const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0); - const deltaDown = clamp(delta, -expandDown, collapseDown); - - this.resize(index, deltaDown); - delta -= deltaDown; - } - - if (delta !== 0 && index > 0) { - const upIndexes = range(index - 1, -1); - const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0); - const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0); - const deltaUp = clamp(-delta, -collapseUp, expandUp); - - this.resize(index - 1, deltaUp); - } - - this.distributeEmptySpace(); - this.layoutViews(); - this.saveProportions(); + item.size = size; + this.relayout(lowPriorityIndexes, highPriorityIndexes); this.state = State.Idle; } distributeViewSizes(): void { - const size = Math.floor(this.size / this.viewItems.length); + const flexibleViewItems: ViewItem[] = []; + let flexibleSize = 0; - for (let i = 0; i < this.viewItems.length - 1; i++) { - this.resizeView(i, size); + for (const item of this.viewItems) { + if (item.maximumSize - item.minimumSize > 0) { + flexibleViewItems.push(item); + flexibleSize += item.size; + } } + + const size = Math.floor(flexibleSize / flexibleViewItems.length); + + for (const item of flexibleViewItems) { + item.size = clamp(size, item.minimumSize, item.maximumSize); + } + + const indexes = range(this.viewItems.length); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); + + this.relayout(lowPriorityIndexes, highPriorityIndexes); } getViewSize(index: number): number { @@ -514,6 +678,15 @@ export class SplitView extends Disposable { return this.viewItems[index].size; } + private relayout(lowPriorityIndexes?: number[], highPriorityIndexes?: number[]): void { + const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + + this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes); + this.distributeEmptySpace(); + this.layoutViews(); + this.saveProportions(); + } + private resize( index: number, delta: number, @@ -521,7 +694,9 @@ export class SplitView extends Disposable { lowPriorityIndexes?: number[], highPriorityIndexes?: number[], overloadMinDelta: number = Number.NEGATIVE_INFINITY, - overloadMaxDelta: number = Number.POSITIVE_INFINITY + overloadMaxDelta: number = Number.POSITIVE_INFINITY, + snapBefore?: ISashDragSnapState, + snapAfter?: ISashDragSnapState ): number { if (index < 0 || index >= this.viewItems.length) { return 0; @@ -550,18 +725,38 @@ export class SplitView extends Disposable { const downItems = downIndexes.map(i => this.viewItems[i]); const downSizes = downIndexes.map(i => sizes[i]); - const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.minimumSize - sizes[i]), 0); - const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0); - const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0); - const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.maximumSize), 0); + const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0); + const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0); + const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0); + const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0); const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta); const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta); + let snapped = false; + + if (snapBefore) { + const snapView = this.viewItems[snapBefore.index]; + const visible = delta >= snapBefore.limitDelta; + snapped = visible !== snapView.visible; + snapView.visible = visible; + } + + if (!snapped && snapAfter) { + const snapView = this.viewItems[snapAfter.index]; + const visible = delta < snapAfter.limitDelta; + snapped = visible !== snapView.visible; + snapView.visible = visible; + } + + if (snapped) { + return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta); + } + delta = clamp(delta, minDelta, maxDelta); for (let i = 0, deltaUp = delta; i < upItems.length; i++) { const item = upItems[i]; - const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize); + const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize); const viewDelta = size - upSizes[i]; deltaUp -= viewDelta; @@ -570,7 +765,7 @@ export class SplitView extends Disposable { for (let i = 0, deltaDown = delta; i < downItems.length; i++) { const item = downItems[i]; - const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize); + const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize); const viewDelta = size - downSizes[i]; deltaDown += viewDelta; @@ -580,13 +775,29 @@ export class SplitView extends Disposable { return delta; } - private distributeEmptySpace(): void { - let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + private distributeEmptySpace(lowPriorityIndex?: number): void { + const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); let emptyDelta = this.size - contentSize; - for (let i = this.viewItems.length - 1; emptyDelta !== 0 && i >= 0; i--) { - const item = this.viewItems[i]; - const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize); + const indexes = range(this.viewItems.length - 1, -1); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); + + for (const index of highPriorityIndexes) { + pushToStart(indexes, index); + } + + for (const index of lowPriorityIndexes) { + pushToEnd(indexes, index); + } + + if (typeof lowPriorityIndex === 'number') { + pushToEnd(indexes, lowPriorityIndex); + } + + for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) { + const item = this.viewItems[indexes[i]]; + const size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize); const viewDelta = size - item.size; emptyDelta -= viewDelta; @@ -606,31 +817,43 @@ export class SplitView extends Disposable { // Update sashes enablement let previous = false; - const collapsesDown = this.viewItems.map(i => previous = (i.size - i.view.minimumSize > 0) || previous); + const collapsesDown = this.viewItems.map(i => previous = (i.size - i.minimumSize > 0) || previous); previous = false; - const expandsDown = this.viewItems.map(i => previous = (i.view.maximumSize - i.size > 0) || previous); + const expandsDown = this.viewItems.map(i => previous = (i.maximumSize - i.size > 0) || previous); const reverseViews = [...this.viewItems].reverse(); previous = false; - const collapsesUp = reverseViews.map(i => previous = (i.size - i.view.minimumSize > 0) || previous).reverse(); + const collapsesUp = reverseViews.map(i => previous = (i.size - i.minimumSize > 0) || previous).reverse(); previous = false; - const expandsUp = reverseViews.map(i => previous = (i.view.maximumSize - i.size > 0) || previous).reverse(); + const expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse(); - this.sashItems.forEach((s, i) => { - const min = !(collapsesDown[i] && expandsUp[i + 1]); - const max = !(expandsDown[i] && collapsesUp[i + 1]); + this.sashItems.forEach(({ sash }, index) => { + const min = !(collapsesDown[index] && expandsUp[index + 1]); + const max = !(expandsDown[index] && collapsesUp[index + 1]); if (min && max) { - s.sash.state = SashState.Disabled; + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) { + sash.state = SashState.Minimum; + } else if (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) { + sash.state = SashState.Maximum; + } else { + sash.state = SashState.Disabled; + } } else if (min && !max) { - s.sash.state = SashState.Minimum; + sash.state = SashState.Minimum; } else if (!min && max) { - s.sash.state = SashState.Maximum; + sash.state = SashState.Maximum; } else { - s.sash.state = SashState.Enabled; + sash.state = SashState.Enabled; } + // } }); } @@ -648,10 +871,40 @@ export class SplitView extends Disposable { return 0; } + private findFirstSnapIndex(indexes: number[]): number | undefined { + // visible views first + for (const index of indexes) { + const viewItem = this.viewItems[index]; + + if (!viewItem.visible) { + continue; + } + + if (viewItem.snap) { + return index; + } + } + + // then, hidden views + for (const index of indexes) { + const viewItem = this.viewItems[index]; + + if (viewItem.visible && viewItem.maximumSize - viewItem.minimumSize > 0) { + return undefined; + } + + if (!viewItem.visible && viewItem.snap) { + return index; + } + } + + return undefined; + } + dispose(): void { super.dispose(); - this.viewItems.forEach(i => i.disposable.dispose()); + this.viewItems.forEach(i => i.dispose()); this.viewItems = []; this.sashItems.forEach(i => i.disposable.dispose()); diff --git a/src/vs/base/browser/ui/toolbar/toolbar.css b/src/vs/base/browser/ui/toolbar/toolbar.css index f1fdad313ab..47669712253 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.css +++ b/src/vs/base/browser/ui/toolbar/toolbar.css @@ -17,5 +17,5 @@ } .hc-black .monaco-toolbar .action-label.toolbar-toggle-more { - background-image: url('ellipsis-dark.svg'); + background-image: url('ellipsis-hc.svg'); } \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index a034736f2f5..7624d5b1fbe 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1183,7 +1183,7 @@ export abstract class AbstractTree implements IDisposable constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private _options: IAbstractTreeOptions = {} ) { const treeDelegate = new ComposedTreeDelegate>(delegate); diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index e31422edf6a..4421bce8de1 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -320,7 +320,7 @@ export class AsyncDataTree implements IDisposable get onDidFocus(): Event { return this.tree.onDidFocus; } get onDidBlur(): Event { return this.tree.onDidBlur; } - get onDidChangeCollapseState(): Event, TFilterData>> { return this.tree.onDidChangeCollapseState; } + get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.tree.onDidChangeCollapseState; } get onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; } @@ -340,7 +340,7 @@ export class AsyncDataTree implements IDisposable constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private dataSource: IAsyncDataSource, options: IAsyncDataTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/compressedObjectTree.ts b/src/vs/base/browser/ui/tree/compressedObjectTree.ts new file mode 100644 index 00000000000..5d1b80462c5 --- /dev/null +++ b/src/vs/base/browser/ui/tree/compressedObjectTree.ts @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Iterator, ISequence } from 'vs/base/common/iterator'; +import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; +import { ISpliceable } from 'vs/base/common/sequence'; +import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { Event } from 'vs/base/common/event'; +import { CompressedTreeModel, ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; + +export interface IObjectTreeOptions extends IAbstractTreeOptions { + sorter?: ITreeSorter; +} + +export class CompressedObjectTree, TFilterData = void> extends AbstractTree | null, TFilterData, T | null> { + + protected model: CompressedTreeModel; + + get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.model.onDidChangeCollapseState; } + + constructor( + container: HTMLElement, + delegate: IListVirtualDelegate>, + renderers: ITreeRenderer, TFilterData, any>[], + options: IObjectTreeOptions, TFilterData> = {} + ) { + super(container, delegate, renderers, options); + } + + setChildren( + element: T | null, + children?: ISequence> + ): Iterator> { + return this.model.setChildren(element, children); + } + + rerender(element?: T): void { + if (element === undefined) { + this.view.rerender(); + return; + } + + this.model.rerender(element); + } + + resort(element: T, recursive = true): void { + this.model.resort(element, recursive); + } + + protected createModel(view: ISpliceable, TFilterData>>, options: IObjectTreeOptions, TFilterData>): ITreeModel | null, TFilterData, T | null> { + return new CompressedTreeModel(view, options); + } +} diff --git a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts new file mode 100644 index 00000000000..339dfdbbe9e --- /dev/null +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -0,0 +1,418 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ISpliceable } from 'vs/base/common/sequence'; +import { Iterator, ISequence } from 'vs/base/common/iterator'; +import { Event } from 'vs/base/common/event'; +import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; +import { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; + +export interface ICompressedTreeElement extends ITreeElement { + readonly children?: Iterator> | ICompressedTreeElement[]; + readonly incompressible?: boolean; +} + +export interface ICompressedTreeNode { + readonly elements: T[]; + readonly incompressible: boolean; +} + +export function compress(element: ICompressedTreeElement): ITreeElement> { + const elements = [element.element]; + const incompressible = element.incompressible || false; + + let childrenIterator: Iterator>; + let children: ITreeElement[]; + + while (true) { + childrenIterator = Iterator.from(element.children); + children = Iterator.collect(childrenIterator, 2); + + if (children.length !== 1) { + break; + } + + element = children[0]; + + if (element.incompressible) { + break; + } + + elements.push(element.element); + } + + return { + element: { elements, incompressible }, + children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress) + }; +} + +export function _decompress(element: ITreeElement>, index = 0): ICompressedTreeElement { + let children: Iterator>; + + if (index < element.element.elements.length - 1) { + children = Iterator.single(_decompress(element, index + 1)); + } else { + children = Iterator.map(Iterator.from(element.children), el => _decompress(el, 0)); + } + + if (index === 0 && element.element.incompressible) { + return { element: element.element.elements[index], children, incompressible: true }; + } + + return { element: element.element.elements[index], children }; +} + +export function decompress(element: ITreeElement>): ICompressedTreeElement { + return _decompress(element, 0); +} + +export function splice(treeElement: ICompressedTreeElement, element: T, children: Iterator>): ICompressedTreeElement { + if (treeElement.element === element) { + return { element, children }; + } + + return { + ...treeElement, + children: Iterator.map(Iterator.from(treeElement.children), e => splice(e, element, children)) + }; +} + +export interface ICompressedTreeModelOptions extends IObjectTreeModelOptions, TFilterData> { } + +export class CompressedTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> { + + readonly rootRef = null; + + get onDidSplice(): Event | null, TFilterData>> { return this.model.onDidSplice; } + get onDidChangeCollapseState(): Event, TFilterData>> { return this.model.onDidChangeCollapseState; } + get onDidChangeRenderNodeCount(): Event, TFilterData>> { return this.model.onDidChangeRenderNodeCount; } + + private model: ObjectTreeModel, TFilterData>; + private nodes = new Map>(); + + get size(): number { return this.nodes.size; } + + constructor(list: ISpliceable, TFilterData>>, options: ICompressedTreeModelOptions = {}) { + this.model = new ObjectTreeModel(list, options); + } + + setChildren( + element: T | null, + children: ISequence> | undefined, + onDidCreateNode?: (node: ITreeNode, TFilterData>) => void, + onDidDeleteNode?: (node: ITreeNode, TFilterData>) => void + ): Iterator> { + const insertedElements = new Set(); + const _onDidCreateNode = (node: ITreeNode, TFilterData>) => { + for (const element of node.element.elements) { + insertedElements.add(element); + this.nodes.set(element, node.element); + } + + // if (this.identityProvider) { + // const id = this.identityProvider.getId(node.element).toString(); + // insertedElementIds.add(id); + // this.nodesByIdentity.set(id, node); + // } + + if (onDidCreateNode) { + onDidCreateNode(node); + } + }; + + const _onDidDeleteNode = (node: ITreeNode, TFilterData>) => { + for (const element of node.element.elements) { + if (!insertedElements.has(element)) { + this.nodes.delete(element); + } + } + + // if (this.identityProvider) { + // const id = this.identityProvider.getId(node.element).toString(); + // if (!insertedElementIds.has(id)) { + // this.nodesByIdentity.delete(id); + // } + // } + + if (onDidDeleteNode) { + onDidDeleteNode(node); + } + }; + + if (element === null) { + const compressedChildren = Iterator.map(Iterator.from(children), compress); + const result = this.model.setChildren(null, compressedChildren, _onDidCreateNode, _onDidDeleteNode); + return Iterator.map(result, decompress); + } + + const compressedNode = this.nodes.get(element); + const node = this.model.getNode(compressedNode) as ITreeNode, TFilterData>; + const parent = node.parent!; + + const decompressedElement = decompress(node); + const splicedElement = splice(decompressedElement, element, Iterator.from(children)); + const recompressedElement = compress(splicedElement); + + const parentChildren = parent.children + .map(child => child === node ? recompressedElement : child); + + this.model.setChildren(parent.element, parentChildren, _onDidCreateNode, _onDidDeleteNode); + + // TODO + return Iterator.empty(); + } + + getListIndex(location: T | null): number { + const node = this.getCompressedNode(location); + return this.model.getListIndex(node); + } + + getListRenderCount(location: T | null): number { + const node = this.getCompressedNode(location); + return this.model.getListRenderCount(node); + } + + getNode(location?: T | null | undefined): ITreeNode | null, TFilterData> { + if (typeof location === 'undefined') { + return this.model.getNode(); + } + + const node = this.getCompressedNode(location); + return this.model.getNode(node); + } + + // TODO: review this + getNodeLocation(node: ITreeNode, TFilterData>): T | null { + const compressedNode = this.model.getNodeLocation(node); + + if (compressedNode === null) { + return null; + } + + return compressedNode.elements[compressedNode.elements.length - 1]; + } + + // TODO: review this + getParentNodeLocation(location: T | null): T | null { + const compressedNode = this.getCompressedNode(location); + const parentNode = this.model.getParentNodeLocation(compressedNode); + + if (parentNode === null) { + return null; + } + + return parentNode.elements[parentNode.elements.length - 1]; + } + + getParentElement(location: T | null): ICompressedTreeNode | null { + const compressedNode = this.getCompressedNode(location); + return this.model.getParentElement(compressedNode); + } + + getFirstElementChild(location: T | null): ICompressedTreeNode | null | undefined { + const compressedNode = this.getCompressedNode(location); + return this.model.getFirstElementChild(compressedNode); + } + + getLastElementAncestor(location?: T | null | undefined): ICompressedTreeNode | null | undefined { + const compressedNode = typeof location === 'undefined' ? undefined : this.getCompressedNode(location); + return this.model.getLastElementAncestor(compressedNode); + } + + isCollapsible(location: T | null): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.isCollapsible(compressedNode); + } + + isCollapsed(location: T | null): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.isCollapsed(compressedNode); + } + + setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.setCollapsed(compressedNode, collapsed, recursive); + } + + expandTo(location: T | null): void { + const compressedNode = this.getCompressedNode(location); + this.model.expandTo(compressedNode); + } + + rerender(location: T | null): void { + const compressedNode = this.getCompressedNode(location); + this.model.rerender(compressedNode); + } + + refilter(): void { + this.model.refilter(); + } + + resort(location: T | null = null, recursive = true): void { + const compressedNode = this.getCompressedNode(location); + this.model.resort(compressedNode, recursive); + } + + private getCompressedNode(element: T | null): ICompressedTreeNode | null { + if (element === null) { + return null; + } + + const node = this.nodes.get(element); + + if (!node) { + throw new Error(`Tree element not found: ${element}`); + } + + return node; + } +} + +export type ElementMapper = (elements: T[]) => T; +export const DefaultElementMapper: ElementMapper = elements => elements[elements.length - 1]; + +export type NodeMapper = (node: ITreeNode | null, TFilterData>) => ITreeNode; + +function mapNode(elementMapper: ElementMapper, node: ITreeNode | null, TFilterData>): ITreeNode { + return { + ...node, + element: node.element === null ? null : elementMapper(node.element.elements), + children: node.children.map(child => mapNode(elementMapper, child)), + parent: typeof node.parent === 'undefined' ? node.parent : mapNode(elementMapper, node.parent) + }; +} + +function createNodeMapper(elementMapper: ElementMapper): NodeMapper { + return node => mapNode(elementMapper, node); +} + +export interface ICompressedObjectTreeModelOptions extends ICompressedTreeModelOptions { + readonly elementMapper?: ElementMapper; +} + +export class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { + + readonly rootRef = null; + + get onDidSplice(): Event> { + return Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({ + insertedNodes: insertedNodes.map(this.mapNode), + deletedNodes: deletedNodes.map(this.mapNode), + })); + } + + get onDidChangeCollapseState(): Event> { + return Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({ + node: this.mapNode(node), + deep + })); + } + + get onDidChangeRenderNodeCount(): Event> { + return Event.map(this.model.onDidChangeRenderNodeCount, this.mapNode); + } + + private mapElement: ElementMapper; + private mapNode: NodeMapper; + private model: CompressedTreeModel; + + constructor( + list: ISpliceable, TFilterData>>, + options: ICompressedObjectTreeModelOptions = {} + ) { + this.mapElement = options.elementMapper || DefaultElementMapper; + this.mapNode = createNodeMapper(this.mapElement); + this.model = new CompressedTreeModel(list, options); + } + + setChildren( + element: T | null, + children: ISequence> | undefined + ): Iterator> { + this.model.setChildren(element, children); + + // TODO + return Iterator.empty(); + } + + getListIndex(location: T | null): number { + return this.model.getListIndex(location); + } + + getListRenderCount(location: T | null): number { + return this.model.getListRenderCount(location); + } + + getNode(location?: T | null | undefined): ITreeNode { + return this.mapNode(this.model.getNode(location)); + } + + getNodeLocation(node: ITreeNode): T | null { + return node.element; + } + + getParentNodeLocation(location: T | null): T | null { + return this.model.getParentNodeLocation(location); + } + + getParentElement(location: T | null): T | null { + const result = this.model.getParentElement(location); + + if (result === null) { + return result; + } + + return this.mapElement(result.elements); + } + + getFirstElementChild(location: T | null): T | null | undefined { + const result = this.model.getFirstElementChild(location); + + if (result === null || typeof result === 'undefined') { + return result; + } + + return this.mapElement(result.elements); + } + + getLastElementAncestor(location?: T | null | undefined): T | null | undefined { + const result = this.model.getLastElementAncestor(location); + + if (result === null || typeof result === 'undefined') { + return result; + } + + return this.mapElement(result.elements); + } + + isCollapsible(location: T | null): boolean { + return this.model.isCollapsible(location); + } + + isCollapsed(location: T | null): boolean { + return this.model.isCollapsed(location); + } + + setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean { + return this.model.setCollapsed(location, collapsed, recursive); + } + + expandTo(location: T | null): void { + return this.model.expandTo(location); + } + + rerender(location: T | null): void { + return this.model.rerender(location); + } + + refilter(): void { + return this.model.refilter(); + } + + resort(element: T | null = null, recursive = true): void { + return this.model.resort(element, recursive); + } +} \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index bb93ca31fad..9f51021a2e0 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -32,7 +32,7 @@ export class DataTree extends AbstractTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private dataSource: IDataSource, options: IDataTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/indexTree.ts b/src/vs/base/browser/ui/tree/indexTree.ts index 54eb0e103e6..4378ffd3e1a 100644 --- a/src/vs/base/browser/ui/tree/indexTree.ts +++ b/src/vs/base/browser/ui/tree/indexTree.ts @@ -20,7 +20,7 @@ export class IndexTree extends AbstractTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private rootElement: T, options: IIndexTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index 38bca41901c..51873462959 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -7,7 +7,7 @@ import { Iterator, ISequence } from 'vs/base/common/iterator'; import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; import { ISpliceable } from 'vs/base/common/sequence'; import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree'; -import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; +import { ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { Event } from 'vs/base/common/event'; @@ -17,14 +17,14 @@ export interface IObjectTreeOptions extends IAbstractTree export class ObjectTree, TFilterData = void> extends AbstractTree { - protected model: ObjectTreeModel; + protected model: IObjectTreeModel; - get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } + get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], options: IObjectTreeOptions = {} ) { super(container, delegate, renderers, options); @@ -32,11 +32,9 @@ export class ObjectTree, TFilterData = void> extends setChildren( element: T | null, - children?: ISequence>, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void + children?: ISequence> ): Iterator> { - return this.model.setChildren(element, children, onDidCreateNode, onDidDeleteNode); + return this.model.setChildren(element, children); } rerender(element?: T): void { diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index d836e39f116..626d1264daa 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -10,12 +10,19 @@ import { Event } from 'vs/base/common/event'; import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; import { IIdentityProvider } from 'vs/base/browser/ui/list/list'; +export type ITreeNodeCallback = (node: ITreeNode) => void; + +export interface IObjectTreeModel, TFilterData extends NonNullable = void> extends ITreeModel { + setChildren(element: T | null, children: ISequence> | undefined): Iterator>; + resort(element?: T | null, recursive?: boolean): void; +} + export interface IObjectTreeModelOptions extends IIndexTreeModelOptions { readonly sorter?: ITreeSorter; readonly identityProvider?: IIdentityProvider; } -export class ObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel { +export class ObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { readonly rootRef = null; @@ -51,9 +58,9 @@ export class ObjectTreeModel, TFilterData extends Non setChildren( element: T | null, children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void - ): Iterator> { + onDidCreateNode?: ITreeNodeCallback, + onDidDeleteNode?: ITreeNodeCallback + ): Iterator> { const location = this.getElementLocation(element); return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode); } @@ -61,9 +68,9 @@ export class ObjectTreeModel, TFilterData extends Non private _setChildren( location: number[], children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void - ): Iterator> { + onDidCreateNode?: ITreeNodeCallback, + onDidDeleteNode?: ITreeNodeCallback + ): Iterator> { const insertedElements = new Set(); const insertedElementIds = new Set(); @@ -107,7 +114,7 @@ export class ObjectTreeModel, TFilterData extends Non _onDidDeleteNode ); - return result; + return result as Iterator>; } private preserveCollapseState(elements: ISequence> | undefined): ISequence> { @@ -144,7 +151,7 @@ export class ObjectTreeModel, TFilterData extends Non }); } - rerender(element: T): void { + rerender(element: T | null): void { const location = this.getElementLocation(element); this.model.rerender(location); } @@ -190,32 +197,32 @@ export class ObjectTreeModel, TFilterData extends Non return this.model.getLastElementAncestor(location); } - getListIndex(element: T): number { + getListIndex(element: T | null): number { const location = this.getElementLocation(element); return this.model.getListIndex(location); } - getListRenderCount(element: T): number { + getListRenderCount(element: T | null): number { const location = this.getElementLocation(element); return this.model.getListRenderCount(location); } - isCollapsible(element: T): boolean { + isCollapsible(element: T | null): boolean { const location = this.getElementLocation(element); return this.model.isCollapsible(location); } - isCollapsed(element: T): boolean { + isCollapsed(element: T | null): boolean { const location = this.getElementLocation(element); return this.model.isCollapsed(location); } - setCollapsed(element: T, collapsed?: boolean, recursive?: boolean): boolean { + setCollapsed(element: T | null, collapsed?: boolean, recursive?: boolean): boolean { const location = this.getElementLocation(element); return this.model.setCollapsed(location, collapsed, recursive); } - expandTo(element: T): void { + expandTo(element: T | null): void { const location = this.getElementLocation(element); this.model.expandTo(location); } @@ -238,11 +245,15 @@ export class ObjectTreeModel, TFilterData extends Non return node; } - getNodeLocation(node: ITreeNode): T { + getNodeLocation(node: ITreeNode): T | null { return node.element; } - getParentNodeLocation(element: T): T | null { + getParentNodeLocation(element: T | null): T | null { + if (element === null) { + throw new Error(`Invalid getParentNodeLocation call`); + } + const node = this.nodes.get(element); if (!node) { diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 80b30fa4c55..5f9f2e14d69 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -124,6 +124,7 @@ export interface ITreeModel { setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean; expandTo(location: TRef): void; + rerender(location: TRef): void; refilter(): void; } diff --git a/src/vs/base/common/buffer.ts b/src/vs/base/common/buffer.ts index 3ae9379ee7a..99d5e5274e1 100644 --- a/src/vs/base/common/buffer.ts +++ b/src/vs/base/common/buffer.ts @@ -141,18 +141,13 @@ export interface VSBufferReadable { read(): VSBuffer | null; } -/** - * A buffer readable stream emits data to listeners. The stream - * will only start emitting when the first data listener has - * been added or the resume() method has been called. - */ -export interface VSBufferReadableStream { +export interface ReadableStream { /** * The 'data' event is emitted whenever the stream is * relinquishing ownership of a chunk of data to a consumer. */ - on(event: 'data', callback: (chunk: VSBuffer) => void): void; + on(event: 'data', callback: (chunk: T) => void): void; /** * Emitted when any error occurs. @@ -169,16 +164,25 @@ export interface VSBufferReadableStream { /** * Stops emitting any events until resume() is called. */ - pause(): void; + pause?(): void; /** * Starts emitting events again after pause() was called. */ - resume(): void; + resume?(): void; /** * Destroys the stream and stops emitting any event. */ + destroy?(): void; +} + +/** + * A readable stream that sends data via VSBuffer. + */ +export interface VSBufferReadableStream extends ReadableStream { + pause(): void; + resume(): void; destroy(): void; } @@ -245,6 +249,19 @@ export function bufferToStream(buffer: VSBuffer): VSBufferReadableStream { return stream; } +/** + * Helper to create a VSBufferStream from a Uint8Array stream. + */ +export function toVSBufferReadableStream(stream: ReadableStream): VSBufferReadableStream { + const vsbufferStream = writeableBufferStream(); + + stream.on('data', data => vsbufferStream.write(typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data))); + stream.on('end', () => vsbufferStream.end()); + stream.on('error', error => vsbufferStream.error(error)); + + return vsbufferStream; +} + /** * Helper to create a VSBufferStream that can be pushed * buffers to. Will only start to emit data when a listener diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 8b89e002422..2a423637149 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -326,6 +326,20 @@ export namespace Event { return result.event; } + export interface DOMEventEmitter { + addEventListener(event: string | symbol, listener: Function): void; + removeEventListener(event: string | symbol, listener: Function): void; + } + + export function fromDOMEventEmitter(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event { + const fn = (...args: any[]) => result.fire(map(...args)); + const onFirstListenerAdd = () => emitter.addEventListener(eventName, fn); + const onLastListenerRemove = () => emitter.removeEventListener(eventName, fn); + const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove }); + + return result.event; + } + export function fromPromise(promise: Promise): Event { const emitter = new Emitter(); let shouldEmit = false; diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 645937c3375..d01c32668ca 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -414,7 +414,7 @@ export function createMatches(score: undefined | FuzzyScore): IMatch[] { return res; } -const _maxLen = 53; +const _maxLen = 128; function initTable() { const table: number[][] = []; diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 6746c06c9be..78fc5e97ce1 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -334,7 +334,6 @@ function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | if (!extpath.isEqualOrParent(path, arg2.base)) { return null; } - return parsedPattern(paths.relative(arg2.base, path), basename); }; } diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index 201e378e11e..ac7c8ed3a91 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -92,3 +92,25 @@ export function removeMarkdownEscapes(text: string): string { } return text.replace(/\\([\\`*_{}[\]()#+\-.!])/g, '$1'); } + +export function parseHrefAndDimensions(href: string): { href: string, dimensions: string[] } { + const dimensions: string[] = []; + const splitted = href.split('|').map(s => s.trim()); + href = splitted[0]; + const parameters = splitted[1]; + if (parameters) { + const heightFromParams = /height=(\d+)/.exec(parameters); + const widthFromParams = /width=(\d+)/.exec(parameters); + const height = heightFromParams ? heightFromParams[1] : ''; + const width = widthFromParams ? widthFromParams[1] : ''; + const widthIsFinite = isFinite(parseInt(width)); + const heightIsFinite = isFinite(parseInt(height)); + if (widthIsFinite) { + dimensions.push(`width="${width}"`); + } + if (heightIsFinite) { + dimensions.push(`height="${height}"`); + } + } + return { href, dimensions }; +} diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 038bf263222..db53b8aef57 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -29,6 +29,21 @@ export module Iterator { return _empty; } + export function single(value: T): Iterator { + let done = false; + + return { + next(): IteratorResult { + if (done) { + return FIN; + } + + done = true; + return { done: false, value }; + } + }; + } + export function fromArray(array: T[], index = 0, length = array.length): Iterator { return { next(): IteratorResult { @@ -86,11 +101,47 @@ export module Iterator { } } - export function collect(iterator: Iterator): T[] { + export function collect(iterator: Iterator, atMost: number = Number.POSITIVE_INFINITY): T[] { const result: T[] = []; - forEach(iterator, value => result.push(value)); + + if (atMost === 0) { + return result; + } + + let i = 0; + + for (let next = iterator.next(); !next.done; next = iterator.next()) { + result.push(next.value); + + if (++i >= atMost) { + break; + } + } + return result; } + + export function concat(...iterators: Iterator[]): Iterator { + let i = 0; + + return { + next() { + if (i >= iterators.length) { + return FIN; + } + + const iterator = iterators[i]; + const result = iterator.next(); + + if (result.done) { + i++; + return this.next(); + } + + return result; + } + }; + } } export type ISequence = Iterator | T[]; diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index b3a62ede9ff..da0535be422 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -374,12 +374,12 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON let code = text.charCodeAt(pos); // trivia: whitespace - if (isWhiteSpace(code)) { + if (isWhitespace(code)) { do { pos++; value += String.fromCharCode(code); code = text.charCodeAt(pos); - } while (isWhiteSpace(code)); + } while (isWhitespace(code)); return token = SyntaxKind.Trivia; } @@ -517,7 +517,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON } function isUnknownContentCharacter(code: CharacterCodes) { - if (isWhiteSpace(code) || isLineBreak(code)) { + if (isWhitespace(code) || isLineBreak(code)) { return false; } switch (code) { @@ -555,7 +555,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON }; } -function isWhiteSpace(ch: number): boolean { +function isWhitespace(ch: number): boolean { return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed || ch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace || ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark; diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index 66143bb94b7..6be438cee41 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -207,15 +207,50 @@ export class MutableDisposable implements IDisposable { } } +/** + * Wrapper class that stores a disposable that is not currently "owned" by anyone. + * + * Example use cases: + * + * - Express that a function/method will take ownership of a disposable parameter. + * - Express that a function returns a disposable that the caller must explicitly take ownership of. + */ +export class UnownedDisposable extends Disposable { + private _hasBeenAcquired = false; + private _value?: T; + + public constructor(value: T) { + super(); + this._value = value; + } + + public acquire(): T { + if (this._hasBeenAcquired) { + throw new Error('This disposable has already been acquired'); + } + this._hasBeenAcquired = true; + const value = this._value!; + this._value = undefined; + return value; + } + + public dispose() { + super.dispose(); + if (!this._hasBeenAcquired) { + this._hasBeenAcquired = true; + this._value!.dispose(); + this._value = undefined; + } + } +} + export interface IReference extends IDisposable { readonly object: T; } export abstract class ReferenceCollection { - private references: Map = new Map(); - - constructor() { } + private readonly references: Map = new Map(); acquire(key: string): IReference { let reference = this.references.get(key); diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 4cba839fe52..d7371552d30 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 3d42b36dc20..8e07feffaf7 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/node/id.ts b/src/vs/base/node/id.ts index 6f72afeed79..c2faa20632f 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -7,6 +7,7 @@ import * as errors from 'vs/base/common/errors'; import * as uuid from 'vs/base/common/uuid'; import { networkInterfaces } from 'os'; import { TernarySearchTree } from 'vs/base/common/map'; +import { getMac } from 'vs/base/node/macAddress'; // http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/ // VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69 @@ -76,35 +77,25 @@ export const virtualMachineHint: { value(): number } = new class { }; let machineId: Promise; -export function getMachineId(): Promise { - return machineId || (machineId = getMacMachineId() - .then(id => id || uuid.generateUuid())); // fallback, generate a UUID +export async function getMachineId(): Promise { + if (!machineId) { + machineId = (async () => { + const id = await getMacMachineId(); + + return id || uuid.generateUuid(); // fallback, generate a UUID + })(); + } + + return machineId; } -function getMacMachineId(): Promise { - return new Promise(resolve => { - Promise.all([import('crypto'), import('getmac')]).then(([crypto, getmac]) => { - try { - getmac.getMac((error, macAddress) => { - if (!error) { - resolve(crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex')); - } else { - resolve(undefined); - } - }); - - // Timeout due to hang with reduced privileges #58392 - // TODO@sbatten: Remove this when getmac is patched - setTimeout(() => { - resolve(undefined); - }, 10000); - } catch (err) { - errors.onUnexpectedError(err); - resolve(undefined); - } - }, err => { - errors.onUnexpectedError(err); - resolve(undefined); - }); - }); +async function getMacMachineId(): Promise { + try { + const crypto = await import('crypto'); + const macAddress = await getMac(); + return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex'); + } catch (err) { + errors.onUnexpectedError(err); + return undefined; + } } diff --git a/src/vs/base/node/macAddress.ts b/src/vs/base/node/macAddress.ts new file mode 100644 index 00000000000..dd36be22344 --- /dev/null +++ b/src/vs/base/node/macAddress.ts @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { exec } from 'child_process'; +import { isWindows } from 'vs/base/common/platform'; + +const cmdline = { + windows: 'getmac.exe', + unix: '/sbin/ifconfig -a || /sbin/ip link' +}; + +const invalidMacAddresses = [ + '00:00:00:00:00:00', + 'ff:ff:ff:ff:ff:ff', + 'ac:de:48:00:11:22' +]; + +function validateMacAddress(candidate: string): boolean { + let tempCandidate = candidate.replace(/\-/g, ':').toLowerCase(); + for (let invalidMacAddress of invalidMacAddresses) { + if (invalidMacAddress === tempCandidate) { + return false; + } + } + + return true; +} + +export function getMac(): Promise { + return new Promise(async (resolve, reject) => { + const timeout = setTimeout(() => reject('Unable to retrieve mac address (timeout after 10s)'), 10000); + + try { + resolve(await doGetMac()); + } catch (error) { + reject(error); + } finally { + clearTimeout(timeout); + } + }); +} + +function doGetMac(): Promise { + return new Promise((resolve, reject) => { + try { + exec(isWindows ? cmdline.windows : cmdline.unix, { timeout: 10000 }, (err, stdout, stdin) => { + if (err) { + return reject(`Unable to retrieve mac address (${err.toString()})`); + } else { + const regex = /(?:[a-f\d]{2}[:\-]){5}[a-f\d]{2}/gi; + + let match; + while ((match = regex.exec(stdout)) !== null) { + const macAddressCandidate = match[0]; + if (validateMacAddress(macAddressCandidate)) { + return resolve(macAddressCandidate); + } + } + + return reject('Unable to retrieve mac address (unexpected format)'); + } + }); + } catch (err) { + reject(err); + } + }); +} \ No newline at end of file diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 14dca3d5f49..1af9f028c70 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -138,6 +138,20 @@ export async function readdir(path: string): Promise { return handleDirectoryChildren(await promisify(fs.readdir)(path)); } +export async function readdirWithFileTypes(path: string): Promise { + const children = await promisify(fs.readdir)(path, { withFileTypes: true }); + + // Mac: uses NFD unicode form on disk, but we want NFC + // See also https://github.com/nodejs/node/issues/2165 + if (platform.isMacintosh) { + for (const child of children) { + child.name = normalizeNFC(child.name); + } + } + + return children; +} + export function readdirSync(path: string): string[] { return handleDirectoryChildren(fs.readdirSync(path)); } diff --git a/src/vs/base/node/request.ts b/src/vs/base/node/request.ts deleted file mode 100644 index 17731debc5b..00000000000 --- a/src/vs/base/node/request.ts +++ /dev/null @@ -1,183 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { isBoolean, isNumber } from 'vs/base/common/types'; -import * as https from 'https'; -import * as http from 'http'; -import { Stream } from 'stream'; -import { parse as parseUrl } from 'url'; -import { createWriteStream } from 'fs'; -import { assign } from 'vs/base/common/objects'; -import { createGunzip } from 'zlib'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { canceled } from 'vs/base/common/errors'; - -export type Agent = any; - -export interface IRawRequestFunction { - (options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; -} - -export interface IRequestOptions { - type?: string; - url?: string; - user?: string; - password?: string; - headers?: any; - timeout?: number; - data?: string | Stream; - agent?: Agent; - followRedirects?: number; - strictSSL?: boolean; - getRawRequest?(options: IRequestOptions): IRawRequestFunction; -} - -export interface IRequestContext { - // req: http.ClientRequest; - // res: http.ClientResponse; - res: { - headers: { [n: string]: string }; - statusCode?: number; - }; - stream: Stream; -} - -export interface IRequestFunction { - (options: IRequestOptions, token: CancellationToken): Promise; -} - -async function getNodeRequest(options: IRequestOptions): Promise { - const endpoint = parseUrl(options.url!); - const module = endpoint.protocol === 'https:' ? await import('https') : await import('http'); - return module.request; -} - -export function request(options: IRequestOptions, token: CancellationToken): Promise { - let req: http.ClientRequest; - - const rawRequestPromise = options.getRawRequest - ? Promise.resolve(options.getRawRequest(options)) - : Promise.resolve(getNodeRequest(options)); - - return rawRequestPromise.then(rawRequest => { - - return new Promise((c, e) => { - const endpoint = parseUrl(options.url!); - - const opts: https.RequestOptions = { - hostname: endpoint.hostname, - port: endpoint.port ? parseInt(endpoint.port) : (endpoint.protocol === 'https:' ? 443 : 80), - protocol: endpoint.protocol, - path: endpoint.path, - method: options.type || 'GET', - headers: options.headers, - agent: options.agent, - rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true - }; - - if (options.user && options.password) { - opts.auth = options.user + ':' + options.password; - } - - req = rawRequest(opts, (res: http.IncomingMessage) => { - const followRedirects: number = isNumber(options.followRedirects) ? options.followRedirects : 3; - if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && followRedirects > 0 && res.headers['location']) { - request(assign({}, options, { - url: res.headers['location'], - followRedirects: followRedirects - 1 - }), token).then(c, e); - } else { - let stream: Stream = res; - - if (res.headers['content-encoding'] === 'gzip') { - stream = stream.pipe(createGunzip()); - } - - c({ res, stream } as IRequestContext); - } - }); - - req.on('error', e); - - if (options.timeout) { - req.setTimeout(options.timeout); - } - - if (options.data) { - if (typeof options.data === 'string') { - req.write(options.data); - } else { - options.data.pipe(req); - return; - } - } - - req.end(); - - token.onCancellationRequested(() => { - req.abort(); - e(canceled()); - }); - }); - }); -} - -function isSuccess(context: IRequestContext): boolean { - return (context.res.statusCode && context.res.statusCode >= 200 && context.res.statusCode < 300) || context.res.statusCode === 1223; -} - -function hasNoContent(context: IRequestContext): boolean { - return context.res.statusCode === 204; -} - -export function download(filePath: string, context: IRequestContext): Promise { - return new Promise((c, e) => { - const out = createWriteStream(filePath); - - out.once('finish', () => c(undefined)); - context.stream.once('error', e); - context.stream.pipe(out); - }); -} - -export function asText(context: IRequestContext): Promise { - return new Promise((c, e) => { - if (!isSuccess(context)) { - return e('Server returned ' + context.res.statusCode); - } - - if (hasNoContent(context)) { - return c(null); - } - - const buffer: string[] = []; - context.stream.on('data', (d: string) => buffer.push(d)); - context.stream.on('end', () => c(buffer.join(''))); - context.stream.on('error', e); - }); -} - -export function asJson(context: IRequestContext): Promise { - return new Promise((c, e) => { - if (!isSuccess(context)) { - return e('Server returned ' + context.res.statusCode); - } - - if (hasNoContent(context)) { - return c(null); - } - - const buffer: string[] = []; - context.stream.on('data', (d: string) => buffer.push(d)); - context.stream.on('end', () => { - try { - c(JSON.parse(buffer.join(''))); - } catch (err) { - e(err); - } - }); - context.stream.on('error', e); - }); -} diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 6292487e1c1..9715105baa3 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/base/parts/storage/common/storage.ts b/src/vs/base/parts/storage/common/storage.ts index 3f3892a8e19..03dedeca57f 100644 --- a/src/vs/base/parts/storage/common/storage.ts +++ b/src/vs/base/parts/storage/common/storage.ts @@ -74,7 +74,7 @@ export class Storage extends Disposable implements IStorage { private static readonly DEFAULT_FLUSH_DELAY = 100; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - get onDidChangeStorage(): Event { return this._onDidChangeStorage.event; } + readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; private state = StorageState.None; diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index 6852c0c727e..2042f576d55 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -447,13 +447,13 @@ export class TreeView extends HeightMap { private onHiddenScrollTop: number | null = null; private readonly _onDOMFocus = new Emitter(); - get onDOMFocus(): Event { return this._onDOMFocus.event; } + readonly onDOMFocus: Event = this._onDOMFocus.event; private readonly _onDOMBlur = new Emitter(); - get onDOMBlur(): Event { return this._onDOMBlur.event; } + readonly onDOMBlur: Event = this._onDOMBlur.event; private readonly _onDidScroll = new Emitter(); - get onDidScroll(): Event { return this._onDidScroll.event; } + readonly onDidScroll: Event = this._onDidScroll.event; constructor(context: _.ITreeContext, container: HTMLElement) { super(); diff --git a/src/vs/base/test/browser/ui/grid/grid.test.ts b/src/vs/base/test/browser/ui/grid/grid.test.ts index 7385b3ca4d6..092f3007082 100644 --- a/src/vs/base/test/browser/ui/grid/grid.test.ts +++ b/src/vs/base/test/browser/ui/grid/grid.test.ts @@ -8,6 +8,15 @@ import { Direction, getRelativeLocation, Orientation, SerializableGrid, ISeriali import { TestView, nodesToArrays } from './util'; import { deepClone } from 'vs/base/common/objects'; +// Simple example: +// +-----+---------------+ +// | 4 | 2 | +// +-----+---------+-----+ +// | 1 | | +// +---------------+ 3 | +// | 5 | | +// +---------------+-----+ + suite('Grid', function () { let container: HTMLElement; @@ -798,4 +807,222 @@ suite('SerializableGrid', function () { height: 1 }); }); + + test('serialize should store visibility and previous size', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view5, false); + + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 0]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200 }, + { type: 'leaf', data: { name: 'view2' }, size: 600 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 400 }, + { type: 'leaf', data: { name: 'view5' }, size: 100, visible: false } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 400]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 0]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), false); + + grid2.setViewVisible(view5Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); + + test('serialize should store visibility and previous size even for first leaf', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view4, false); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [0, 200]); + assert.deepEqual(view5.size, [600, 100]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200, visible: false }, + { type: 'leaf', data: { name: 'view2' }, size: 800 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 300 }, + { type: 'leaf', data: { name: 'view5' }, size: 100 } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [800, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [0, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), false); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + + grid2.setViewVisible(view4Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); }); diff --git a/src/vs/base/test/browser/ui/grid/gridview.test.ts b/src/vs/base/test/browser/ui/grid/gridview.test.ts index 76f4e4ac68c..78cc44cc76a 100644 --- a/src/vs/base/test/browser/ui/grid/gridview.test.ts +++ b/src/vs/base/test/browser/ui/grid/gridview.test.ts @@ -22,7 +22,7 @@ suite('Gridview', function () { }); test('empty gridview is empty', function () { - assert.deepEqual(nodesToArrays(gridview.getViews()), []); + assert.deepEqual(nodesToArrays(gridview.getView()), []); gridview.dispose(); }); @@ -43,7 +43,7 @@ suite('Gridview', function () { gridview.addView(views[1], 200, [1]); gridview.addView(views[2], 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -62,7 +62,7 @@ suite('Gridview', function () { gridview.addView((views[1] as TestView[])[0] as IView, 200, [1]); gridview.addView((views[1] as TestView[])[1] as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -71,35 +71,35 @@ suite('Gridview', function () { const view1 = new TestView(20, 20, 20, 20); gridview.addView(view1 as IView, 200, [0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1]); const view2 = new TestView(20, 20, 20, 20); gridview.addView(view2 as IView, 200, [1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, view2]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, view2]); const view3 = new TestView(20, 20, 20, 20); gridview.addView(view3 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view3, view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view3, view2]]); const view4 = new TestView(20, 20, 20, 20); gridview.addView(view4 as IView, 200, [1, 0, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [[view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [[view4, view3], view2]]); const view5 = new TestView(20, 20, 20, 20); gridview.addView(view5 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2]]); const view6 = new TestView(20, 20, 20, 20); gridview.addView(view6 as IView, 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2], view6]); const view7 = new TestView(20, 20, 20, 20); gridview.addView(view7 as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, view7, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, view7, [view4, view3], view2], view6]); const view8 = new TestView(20, 20, 20, 20); gridview.addView(view8 as IView, 200, [1, 1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); gridview.dispose(); }); @@ -107,19 +107,19 @@ suite('Gridview', function () { test('simple layout', function () { gridview.layout(800, 600); - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); assert.deepEqual(view1.size, [800, 600]); assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 }); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [0]); assert.deepEqual(view1.size, [800, 400]); assert.deepEqual(gridview.getViewSize([1]), { width: 800, height: 400 }); assert.deepEqual(view2.size, [800, 200]); assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 200 }); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, 200, [1, 1]); assert.deepEqual(view1.size, [600, 400]); assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 }); @@ -128,7 +128,7 @@ suite('Gridview', function () { assert.deepEqual(view3.size, [200, 400]); assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 }); - const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view4, 200, [0, 0]); assert.deepEqual(view1.size, [600, 400]); assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 }); @@ -139,7 +139,7 @@ suite('Gridview', function () { assert.deepEqual(view4.size, [200, 200]); assert.deepEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 }); - const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view5, 100, [1, 0, 1]); assert.deepEqual(view1.size, [600, 300]); assert.deepEqual(gridview.getViewSize([1, 0, 0]), { width: 600, height: 300 }); @@ -156,30 +156,30 @@ suite('Gridview', function () { test('simple layout with automatic size distribution', function () { gridview.layout(800, 600); - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, Sizing.Distribute, [0]); assert.deepEqual(view1.size, [800, 600]); assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 }); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, Sizing.Distribute, [0]); assert.deepEqual(view1.size, [800, 300]); assert.deepEqual(view2.size, [800, 300]); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, Sizing.Distribute, [1, 1]); assert.deepEqual(view1.size, [400, 300]); assert.deepEqual(view2.size, [800, 300]); assert.deepEqual(view3.size, [400, 300]); - const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view4, Sizing.Distribute, [0, 0]); assert.deepEqual(view1.size, [400, 300]); assert.deepEqual(view2.size, [400, 300]); assert.deepEqual(view3.size, [400, 300]); assert.deepEqual(view4.size, [400, 300]); - const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view5, Sizing.Distribute, [1, 0, 1]); assert.deepEqual(view1.size, [400, 150]); assert.deepEqual(view2.size, [400, 300]); @@ -190,13 +190,13 @@ suite('Gridview', function () { test('addviews before layout call 1', function () { - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [0]); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, 200, [1, 1]); gridview.layout(800, 600); @@ -207,14 +207,13 @@ suite('Gridview', function () { }); test('addviews before layout call 2', function () { - - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [0]); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, 200, [0, 0]); gridview.layout(800, 600); diff --git a/src/vs/base/test/browser/ui/grid/util.ts b/src/vs/base/test/browser/ui/grid/util.ts index 0efdc44851a..39a35736ddd 100644 --- a/src/vs/base/test/browser/ui/grid/util.ts +++ b/src/vs/base/test/browser/ui/grid/util.ts @@ -5,7 +5,8 @@ import * as assert from 'assert'; import { Emitter, Event } from 'vs/base/common/event'; -import { IView, GridNode, isGridBranchNode, } from 'vs/base/browser/ui/grid/gridview'; +import { GridNode, isGridBranchNode } from 'vs/base/browser/ui/grid/gridview'; +import { IView } from 'vs/base/browser/ui/grid/grid'; export class TestView implements IView { @@ -78,4 +79,4 @@ export function nodesToArrays(node: GridNode): any { } else { return node.view; } -} \ No newline at end of file +} diff --git a/src/vs/base/test/browser/ui/splitview/splitview.test.ts b/src/vs/base/test/browser/ui/splitview/splitview.test.ts index 00c698c79cb..504e665f21a 100644 --- a/src/vs/base/test/browser/ui/splitview/splitview.test.ts +++ b/src/vs/base/test/browser/ui/splitview/splitview.test.ts @@ -196,8 +196,8 @@ suite('Splitview', () => { splitview.resizeView(0, 70); assert.equal(view1.size, 70, 'view1 is collapsed'); - assert.equal(view2.size, 110, 'view2 is expanded'); - assert.equal(view3.size, 20, 'view3 stays the same'); + assert.equal(view2.size, 40, 'view2 stays the same'); + assert.equal(view3.size, 90, 'view3 is stretched'); splitview.resizeView(2, 40); @@ -474,10 +474,10 @@ suite('Splitview', () => { splitview.addView(view1, Sizing.Distribute); splitview.addView(view2, Sizing.Distribute); splitview.addView(view3, Sizing.Distribute); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]); splitview.layout(180); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]); splitview.layout(124); assert.deepEqual([view1.size, view2.size, view3.size], [66, 20, 38]); @@ -504,13 +504,13 @@ suite('Splitview', () => { splitview.addView(view1, Sizing.Distribute); splitview.addView(view2, Sizing.Distribute); splitview.addView(view3, Sizing.Distribute); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]); splitview.layout(180); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]); splitview.layout(132); - assert.deepEqual([view1.size, view2.size, view3.size], [44, 20, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [46, 20, 66]); splitview.layout(60); assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]); diff --git a/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts new file mode 100644 index 00000000000..4d03b49a0a8 --- /dev/null +++ b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts @@ -0,0 +1,430 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; +import { Iterator } from 'vs/base/common/iterator'; +import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; +import { ISpliceable } from 'vs/base/common/sequence'; + +interface IResolvedCompressedTreeElement extends ICompressedTreeElement { + readonly element: T; + readonly children?: ICompressedTreeElement[]; +} + +function resolve(treeElement: ICompressedTreeElement): IResolvedCompressedTreeElement { + const result: any = { element: treeElement.element }; + const children = Iterator.collect(Iterator.map(Iterator.from(treeElement.children), resolve)); + + if (treeElement.incompressible) { + result.incompressible = true; + } + + if (children.length > 0) { + result.children = children; + } + + return result; +} + +suite('CompressedObjectTree', function () { + + suite('compress & decompress', function () { + + test('small', function () { + const decompressed: ICompressedTreeElement = { element: 1 }; + const compressed: IResolvedCompressedTreeElement> = + { element: { elements: [1], incompressible: false } }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('no compression', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { element: 11 }, + { element: 12 }, + { element: 13 } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1], incompressible: false }, + children: [ + { element: { elements: [11], incompressible: false } }, + { element: { elements: [12], incompressible: false } }, + { element: { elements: [13], incompressible: false } } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('single hierarchy', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1111 } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11, 111, 1111], incompressible: false } + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('deep compression', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1111 }, + { element: 1112 }, + { element: 1113 }, + { element: 1114 }, + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11, 111], incompressible: false }, + children: [ + { element: { elements: [1111], incompressible: false } }, + { element: { elements: [1112], incompressible: false } }, + { element: { elements: [1113], incompressible: false } }, + { element: { elements: [1114], incompressible: false } }, + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('double deep compression', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1112 }, + { element: 1113 }, + ] + } + ] + }, + { + element: 12, children: [ + { + element: 121, children: [ + { element: 1212 }, + { element: 1213 }, + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1], incompressible: false }, + children: [ + { + element: { elements: [11, 111], incompressible: false }, + children: [ + { element: { elements: [1112], incompressible: false } }, + { element: { elements: [1113], incompressible: false } }, + ] + }, + { + element: { elements: [12, 121], incompressible: false }, + children: [ + { element: { elements: [1212], incompressible: false } }, + { element: { elements: [1213], incompressible: false } }, + ] + } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible leaf', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1111, incompressible: true } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11, 111], incompressible: false }, + children: [ + { element: { elements: [1111], incompressible: true } } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible branch', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, incompressible: true, children: [ + { element: 1111 } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11], incompressible: false }, + children: [ + { element: { elements: [111, 1111], incompressible: true } } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible chain', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, incompressible: true, children: [ + { element: 1111, incompressible: true } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11], incompressible: false }, + children: [ + { + element: { elements: [111], incompressible: true }, + children: [ + { element: { elements: [1111], incompressible: true } } + ] + } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible tree', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, incompressible: true, children: [ + { + element: 111, incompressible: true, children: [ + { element: 1111, incompressible: true } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1], incompressible: false }, + children: [ + { + element: { elements: [11], incompressible: true }, + children: [ + { + element: { elements: [111], incompressible: true }, + children: [ + { element: { elements: [1111], incompressible: true } } + ] + } + ] + } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + }); + + function toSpliceable(arr: T[]): ISpliceable { + return { + splice(start: number, deleteCount: number, elements: T[]): void { + arr.splice(start, deleteCount, ...elements); + } + }; + } + + function toArray(list: ITreeNode>[]): T[][] { + return list.map(i => i.element.elements); + } + + suite('CompressedObjectTreeModel', function () { + + test('ctor', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + assert(model); + assert.equal(list.length, 0); + assert.equal(model.size, 0); + }); + + test('flat', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + + model.setChildren(null, Iterator.fromArray([ + { element: 0 }, + { element: 1 }, + { element: 2 } + ])); + + assert.deepEqual(toArray(list), [[0], [1], [2]]); + assert.equal(model.size, 3); + + model.setChildren(null, Iterator.fromArray([ + { element: 3 }, + { element: 4 }, + { element: 5 }, + ])); + + assert.deepEqual(toArray(list), [[3], [4], [5]]); + assert.equal(model.size, 3); + + model.setChildren(null, Iterator.empty()); + assert.deepEqual(toArray(list), []); + assert.equal(model.size, 0); + }); + + test('nested', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + + model.setChildren(null, Iterator.fromArray([ + { + element: 0, children: Iterator.fromArray([ + { element: 10 }, + { element: 11 }, + { element: 12 }, + ]) + }, + { element: 1 }, + { element: 2 } + ])); + + assert.deepEqual(toArray(list), [[0], [10], [11], [12], [1], [2]]); + assert.equal(model.size, 6); + + model.setChildren(12, Iterator.fromArray([ + { element: 120 }, + { element: 121 } + ])); + + assert.deepEqual(toArray(list), [[0], [10], [11], [12], [120], [121], [1], [2]]); + assert.equal(model.size, 8); + + model.setChildren(0, Iterator.empty()); + assert.deepEqual(toArray(list), [[0], [1], [2]]); + assert.equal(model.size, 3); + + model.setChildren(null, Iterator.empty()); + assert.deepEqual(toArray(list), []); + assert.equal(model.size, 0); + }); + + test('compressed', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + + model.setChildren(null, Iterator.fromArray([ + { + element: 1, children: Iterator.fromArray([{ + element: 11, children: Iterator.fromArray([{ + element: 111, children: Iterator.fromArray([ + { element: 1111 }, + { element: 1112 }, + { element: 1113 }, + ]) + }]) + }]) + } + ])); + + assert.deepEqual(toArray(list), [[1, 11, 111], [1111], [1112], [1113]]); + assert.equal(model.size, 6); + + model.setChildren(11, Iterator.fromArray([ + { element: 111 }, + { element: 112 }, + { element: 113 }, + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113]]); + assert.equal(model.size, 5); + + model.setChildren(113, Iterator.fromArray([ + { element: 1131 } + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131]]); + assert.equal(model.size, 6); + + model.setChildren(1131, Iterator.fromArray([ + { element: 1132 } + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131, 1132]]); + assert.equal(model.size, 7); + + model.setChildren(1131, Iterator.fromArray([ + { element: 1132 }, + { element: 1133 }, + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131], [1132], [1133]]); + assert.equal(model.size, 8); + }); + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index b93e58cfc0a..25cc50d5780 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -470,4 +470,19 @@ suite('Filters', () => { test('List highlight filter: Not all characters from match are highlighterd #66923', () => { assertMatches('foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', fuzzyScore); }); + + test('Autocompletion is matched against truncated filterText to 54 characters #74133', () => { + assertMatches( + 'foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', + fuzzyScore + ); + assertMatches( + 'foo', + 'Gffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + undefined, + fuzzyScore + ); + }); }); diff --git a/src/vs/base/test/common/iterator.test.ts b/src/vs/base/test/common/iterator.test.ts new file mode 100644 index 00000000000..b7a165c5095 --- /dev/null +++ b/src/vs/base/test/common/iterator.test.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { Iterator } from 'vs/base/common/iterator'; + +suite('Iterator', () => { + test('concat', () => { + const first = Iterator.fromArray([1, 2, 3]); + const second = Iterator.fromArray([4, 5, 6]); + const third = Iterator.fromArray([7, 8, 9]); + const actualIterator = Iterator.concat(first, second, third); + const actual = Iterator.collect(actualIterator); + + assert.deepEqual(actual, [1, 2, 3, 4, 5, 6, 7, 8, 9]); + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/node/id.test.ts b/src/vs/base/test/node/id.test.ts index 689bb126d6b..637afa5b550 100644 --- a/src/vs/base/test/node/id.test.ts +++ b/src/vs/base/test/node/id.test.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import * as getmac from 'getmac'; import { getMachineId } from 'vs/base/node/id'; +import { getMac } from 'vs/base/node/macAddress'; suite('ID', () => { @@ -16,9 +16,7 @@ suite('ID', () => { }); test('getMac', () => { - return new Promise((resolve, reject) => { - getmac.getMac((err, macAddress) => err ? reject(err) : resolve(macAddress)); - }).then(macAddress => { + return getMac().then(macAddress => { assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`); }); }); diff --git a/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts index 4f09ad2b56d..060913bbe72 100644 --- a/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -16,6 +16,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { canNormalize } from 'vs/base/common/normalization'; import { VSBuffer } from 'vs/base/common/buffer'; +import { join } from 'path'; const chunkSize = 64 * 1024; const readError = 'Error while reading'; @@ -386,6 +387,31 @@ suite('PFS', () => { } }); + test('readdirWithFileTypes', async () => { + if (canNormalize && typeof process.versions['electron'] !== 'undefined' /* needs electron */) { + const id = uuid.generateUuid(); + const parentDir = path.join(os.tmpdir(), 'vsctests', id); + const testDir = join(parentDir, 'pfs', id); + + const newDir = path.join(testDir, 'öäü'); + await pfs.mkdirp(newDir, 493); + + await pfs.writeFile(join(testDir, 'somefile.txt'), 'contents'); + + assert.ok(fs.existsSync(newDir)); + + const children = await pfs.readdirWithFileTypes(testDir); + + assert.equal(children.some(n => n.name === 'öäü'), true); // Mac always converts to NFD, so + assert.equal(children.some(n => n.isDirectory()), true); + + assert.equal(children.some(n => n.name === 'somefile.txt'), true); + assert.equal(children.some(n => n.isFile()), true); + + await pfs.rimraf(parentDir); + } + }); + test('writeFile (string)', async () => { const smallData = 'Hello World'; const bigData = (new Array(100 * 1024)).join('Large String\n'); diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index 1e742447047..097dd15b3c5 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'; frame-src 'self' {{WEBVIEW_ENDPOINT}} https://*.vscode-webview-test.com; 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 34f321f90df..65fae7c82df 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 a6bb5723f58..2302d162f34 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 00acb515cb3..b85c29ffc4a 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -13,14 +13,14 @@ 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/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { RequestService } from 'vs/platform/request/browser/requestService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { combinedAppender, NullTelemetryService, ITelemetryAppender, NullAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; @@ -37,8 +37,8 @@ import { ILocalizationsService } from 'vs/platform/localizations/common/localiza import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc'; import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { DownloadService } from 'vs/platform/download/node/downloadService'; +import { combinedDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { DownloadService } from 'vs/platform/download/common/downloadService'; import { IDownloadService } from 'vs/platform/download/common/download'; import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner'; @@ -51,6 +51,12 @@ import { SpdLogService } from 'vs/platform/log/node/spdlogService'; import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService'; import { DiagnosticsChannel } 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/electron-browser/diskFileSystemProvider'; +import { Schemas } from 'vs/base/common/network'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ProductService } from 'vs/platform/product/node/productService'; export interface ISharedProcessConfiguration { readonly machineId: string; @@ -109,7 +115,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat services.set(ILogService, logService); services.set(IConfigurationService, configurationService); services.set(IRequestService, new SyncDescriptor(RequestService)); - services.set(IDownloadService, new SyncDescriptor(DownloadService)); + services.set(IProductService, new SyncDescriptor(ProductService)); const mainProcessService = new MainProcessService(server, mainRouter); services.set(IMainProcessService, mainProcessService); @@ -122,6 +128,17 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const dialogChannel = server.getChannel('dialog', activeWindowRouter); services.set(IDialogService, new DialogChannelClient(dialogChannel)); + // Files + const fileService = new FileService(logService); + services.set(IFileService, fileService); + disposables.add(fileService); + + const diskFileSystemProvider = new DiskFileSystemProvider(logService); + disposables.add(diskFileSystemProvider); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + + services.set(IDownloadService, new SyncDescriptor(DownloadService)); + const instantiationService = new InstantiationService(services); let telemetryService: ITelemetryService; @@ -137,12 +154,12 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat if (!extensionDevelopmentLocationURI && !environmentService.args['disable-telemetry'] && product.enableTelemetry) { if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) { appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService); - disposables.add(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data + disposables.add(toDisposable(() => appInsightsAppender!.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } 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-browser/workbench/workbench.html b/src/vs/code/electron-browser/workbench/workbench.html index 7070141cca2..dfac360344a 100644 --- a/src/vs/code/electron-browser/workbench/workbench.html +++ b/src/vs/code/electron-browser/workbench/workbench.html @@ -3,7 +3,7 @@ - + diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index d34f16ef958..785a214c7a3 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -77,16 +77,21 @@ import { HistoryMainService } from 'vs/platform/history/electron-main/historyMai import { URLService } from 'vs/platform/url/common/urlService'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { VSBuffer } from 'vs/base/common/buffer'; import { statSync } from 'fs'; import { ISignService } from 'vs/platform/sign/common/sign'; import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService'; 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 { private static readonly MACHINE_ID_KEY = 'telemetry.machineId'; + private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId'; private windowsMainService: IWindowsMainService | undefined; @@ -162,9 +167,11 @@ export class CodeApplication extends Disposable { event.preventDefault(); }); app.on('remote-get-current-web-contents', event => { - this.logService.trace(`App#on(remote-get-current-web-contents): prevented`); - - event.preventDefault(); + // The driver needs access to web contents + if (!this.environmentService.args.driver) { + this.logService.trace(`App#on(remote-get-current-web-contents): prevented`); + event.preventDefault(); + } }); app.on('web-contents-created', (_event: Electron.Event, contents) => { contents.on('will-attach-webview', (event: Electron.Event, webPreferences, params) => { @@ -236,6 +243,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 */ }); @@ -275,12 +283,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()); @@ -360,8 +362,8 @@ export class CodeApplication extends Disposable { // Resolve unique machine ID this.logService.trace('Resolving machine identifier...'); - const machineId = await this.resolveMachineId(); - this.logService.trace(`Resolved machine identifier: ${machineId}`); + const { machineId, trueMachineId } = await this.resolveMachineId(); + this.logService.trace(`Resolved machine identifier: ${machineId} (trueMachineId: ${trueMachineId})`); // Spawn shared process after the first window has opened and 3s have passed const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); @@ -375,7 +377,7 @@ export class CodeApplication extends Disposable { }); // Services - const appInstantiationService = await this.createServices(machineId, sharedProcess, sharedProcessClient); + const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient); // Create driver if (this.environmentService.driverHandle) { @@ -401,7 +403,7 @@ export class CodeApplication extends Disposable { } } - private async resolveMachineId(): Promise { + private async resolveMachineId(): Promise<{ machineId: string, trueMachineId?: string }> { // We cache the machineId for faster lookups on startup // and resolve it only once initially if not cached @@ -412,12 +414,30 @@ export class CodeApplication extends Disposable { this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId); } - return machineId; + // Check if machineId is hashed iBridge Device + let trueMachineId: string | undefined; + if (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead') { + trueMachineId = this.stateService.getItem(CodeApplication.TRUE_MACHINE_ID_KEY); + if (!trueMachineId) { + trueMachineId = await getMachineId(); + + this.stateService.setItem(CodeApplication.TRUE_MACHINE_ID_KEY, trueMachineId); + } + } + + return { machineId, trueMachineId }; } - private async createServices(machineId: string, sharedProcess: SharedProcess, sharedProcessClient: Promise>): Promise { + private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise>): Promise { const services = new ServiceCollection(); + // Files + const fileService = this._register(new FileService(this.logService)); + services.set(IFileService, fileService); + + const diskFileSystemProvider = this._register(new DiskFileSystemProvider(this.logService)); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + switch (process.platform) { case 'win32': services.set(IUpdateService, new SyncDescriptor(Win32UpdateService)); @@ -462,8 +482,8 @@ 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 config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; + 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])); } else { @@ -555,6 +575,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; @@ -575,8 +598,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(); @@ -627,6 +650,7 @@ export class CodeApplication extends Disposable { urisToOpen: macOpenFiles.map(file => this.getURIToOpenFromPathSync(file)), noRecentEntry, waitMarkerFileURI, + gotoLineMode: false, initialStartup: true }); } @@ -639,6 +663,7 @@ export class CodeApplication extends Disposable { diffMode: args.diff, noRecentEntry, waitMarkerFileURI, + gotoLineMode: args.goto, initialStartup: true }); } @@ -685,7 +710,7 @@ export class CodeApplication extends Disposable { const options: IConnectionOptions = { isBuilt, commit: product.commit, - webSocketFactory: nodeWebSocketFactory, + socketFactory: nodeSocketFactory, addressProvider: { getAddress: () => { return Promise.resolve({ host, port }); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index e71b758a7f7..71891c9bafd 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -26,7 +26,7 @@ import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/ import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import { IRequestService } from 'vs/platform/request/node/request'; +import { IRequestService } from 'vs/platform/request/common/request'; import { RequestService } from 'vs/platform/request/electron-main/requestService'; import * as fs from 'fs'; import { CodeApplication } from 'vs/code/electron-main/app'; @@ -332,7 +332,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/window.ts b/src/vs/code/electron-main/window.ts index 9f5dfa52c02..053c5040879 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -21,10 +21,12 @@ import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/worksp import { IBackupMainService } from 'vs/platform/backup/common/backup'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import * as perf from 'vs/base/common/performance'; -import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { endsWith } from 'vs/base/common/strings'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { IFileService } from 'vs/platform/files/common/files'; +import pkg from 'vs/platform/product/node/package'; const RUN_TEXTMATE_IN_WORKER = true; @@ -76,6 +78,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { config: IWindowCreationOptions, @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IFileService private readonly fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @IThemeMainService private readonly themeMainService: IThemeMainService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @@ -307,7 +310,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { private handleMarketplaceRequests(): void { // Resolve marketplace headers - this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.environmentService); + this.marketplaceHeadersPromise = resolveMarketplaceHeaders(pkg.version, this.environmentService, this.fileService); // Inject headers when requests are incoming const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index ad3025e5c3c..5e50acec4dc 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -207,46 +207,17 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this); this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); - this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.setupNativeHelpers()); + this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex()); } - private setupNativeHelpers(): void { + private installWindowsMutex(): void { if (isWindows) { - - // Setup Windows mutex try { const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; const mutex = new WindowsMutex(product.win32MutexName); once(this.lifecycleService.onWillShutdown)(() => mutex.release()); } catch (e) { this.logService.error(e); - - if (!this.environmentService.isBuilt) { - this.showMessageBox({ - title: product.nameLong, - type: 'warning', - message: 'Failed to load windows-mutex!', - detail: e.toString(), - noLink: true - }); - } - } - - // Dev only: Ensure Windows foreground love module is present - if (!this.environmentService.isBuilt) { - try { - require.__$__nodeRequire('windows-foreground-love'); - } catch (e) { - this.logService.error(e); - - this.showMessageBox({ - title: product.nameLong, - type: 'warning', - message: 'Failed to load windows-foreground-love!', - detail: e.toString(), - noLink: true - }); - } } } } @@ -873,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 9446ef00d59..032287a3b5d 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'; @@ -17,12 +17,12 @@ import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/ import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; -import { IRequestService } from 'vs/platform/request/node/request'; +import { IRequestService } from 'vs/platform/request/common/request'; import { RequestService } from 'vs/platform/request/node/requestService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; @@ -42,6 +42,12 @@ import { LocalizationsService } from 'vs/platform/localizations/node/localizatio import { Schemas } from 'vs/base/common/network'; import { SpdLogService } from 'vs/platform/log/node/spdlogService'; import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry'; +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 { DisposableStore } from 'vs/base/common/lifecycle'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ProductService } from 'vs/platform/product/node/productService'; const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id); const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id); @@ -80,7 +86,7 @@ export class Main { await this.setInstallSource(argv['install-source']); } else if (argv['list-extensions']) { - await this.listExtensions(!!argv['show-versions']); + await this.listExtensions(!!argv['show-versions'], argv['category']); } else if (argv['install-extension']) { const arg = argv['install-extension']; @@ -96,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)); } } @@ -104,8 +110,17 @@ export class Main { return writeFile(this.environmentService.installSourcePath, installSource.slice(0, 30)); } - private async listExtensions(showVersions: boolean): Promise { - const extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + private async listExtensions(showVersions: boolean, category?: string): Promise { + let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + if (category) { + extensions = extensions.filter(e => { + if (e.manifest.categories) { + const lowerCaseCategories: string[] = e.manifest.categories.map(c => c.toLowerCase()); + return lowerCaseCategories.indexOf(category.toLowerCase()) > -1; + } + return false; + }); + } extensions.forEach(e => console.log(getId(e.manifest, showVersions))); } @@ -280,31 +295,46 @@ const eventPrefix = 'monacoworkbench'; export async function main(argv: ParsedArgs): Promise { const services = new ServiceCollection(); + const disposables = new DisposableStore(); const environmentService = new EnvironmentService(argv, process.execPath); const logService: ILogService = new SpdLogService('cli', environmentService.logsPath, getLogLevel(environmentService)); 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); await configurationService.initialize(); services.set(IEnvironmentService, environmentService); services.set(ILogService, logService); services.set(IConfigurationService, configurationService); services.set(IStateService, new SyncDescriptor(StateService)); + services.set(IProductService, new SyncDescriptor(ProductService)); + + // Files + const fileService = new FileService(logService); + disposables.add(fileService); + services.set(IFileService, fileService); + + const diskFileSystemProvider = new DiskFileSystemProvider(logService); + disposables.add(diskFileSystemProvider); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); const instantiationService: IInstantiationService = new InstantiationService(services); - return instantiationService.invokeFunction(accessor => { + return instantiationService.invokeFunction(async accessor => { const envService = accessor.get(IEnvironmentService); const stateService = accessor.get(IStateService); const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService; const services = new ServiceCollection(); + + services.set(IRequestService, new SyncDescriptor(RequestService)); services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); @@ -319,10 +349,11 @@ 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])); + } else { services.set(ITelemetryService, NullTelemetryService); } @@ -330,9 +361,12 @@ export async function main(argv: ParsedArgs): Promise { const instantiationService2 = instantiationService.createChild(services); const main = instantiationService2.createInstance(Main); - return main.run(argv).then(() => { - // Dispose the AI adapter so that remaining data gets flushed. - return combinedAppender(...appenders).dispose(); - }); + try { + await main.run(argv); + // Flush the remaining data in AI adapter. + await combinedAppender(...appenders).flush(); + } finally { + disposables.dispose(); + } }); } \ No newline at end of file diff --git a/src/vs/code/test/electron-main/nativeHelpers.test.ts b/src/vs/code/test/electron-main/nativeHelpers.test.ts new file mode 100644 index 00000000000..ff0f589d511 --- /dev/null +++ b/src/vs/code/test/electron-main/nativeHelpers.test.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { isWindows } from 'vs/base/common/platform'; + +suite('Windows Native Helpers', () => { + test('windows-mutex', async () => { + if (!isWindows) { + return; + } + + const mutex = await import('windows-mutex'); + assert.ok(mutex, 'Unable to load windows-mutex dependency.'); + assert.ok(typeof mutex.isActive === 'function', 'Unable to load windows-mutex dependency.'); + }); + + test('windows-foreground-love', async () => { + if (!isWindows) { + return; + } + + const foregroundLove = await import('windows-foreground-love'); + assert.ok(foregroundLove, 'Unable to load windows-foreground-love dependency.'); + }); +}); \ No newline at end of file diff --git a/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts index e72acd359f3..193ff840ac4 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -316,6 +316,9 @@ export namespace CoreNavigationCommands { const result = this._getColumnSelectResult(cursors.context, cursors.getPrimaryCursor(), cursors.getColumnSelectData(), args); cursors.setStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState))); cursors.setColumnSelectData({ + isReal: true, + fromViewLineNumber: result.fromLineNumber, + fromViewVisualColumn: result.fromVisualColumn, toViewLineNumber: result.toLineNumber, toViewVisualColumn: result.toVisualColumn }); @@ -338,15 +341,15 @@ export namespace CoreNavigationCommands { // validate `args` const validatedPosition = context.model.validatePosition(args.position); + const validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); - let validatedViewPosition: Position; - if (args.viewPosition) { - validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); - } else { - validatedViewPosition = context.convertModelPositionToViewPosition(validatedPosition); + let fromViewLineNumber = prevColumnSelectData.fromViewLineNumber; + let fromViewVisualColumn = prevColumnSelectData.fromViewVisualColumn; + if (!prevColumnSelectData.isReal && args.setAnchorIfNotSet) { + fromViewLineNumber = validatedViewPosition.lineNumber; + fromViewVisualColumn = args.mouseColumn - 1; } - - return ColumnSelection.columnSelect(context.config, context.viewModel, primary.viewState.selection, validatedViewPosition.lineNumber, args.mouseColumn - 1); + return ColumnSelection.columnSelect(context.config, context.viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1); } }); @@ -365,7 +368,7 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectLeft(context.config, context.viewModel, primary.viewState, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectLeft(context.config, context.viewModel, prevColumnSelectData); } }); @@ -384,7 +387,7 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectRight(context.config, context.viewModel, primary.viewState, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectRight(context.config, context.viewModel, prevColumnSelectData); } }); @@ -398,7 +401,7 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectUp(context.config, context.viewModel, primary.viewState, this._isPaged, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectUp(context.config, context.viewModel, prevColumnSelectData, this._isPaged); } } @@ -436,7 +439,7 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectDown(context.config, context.viewModel, primary.viewState, this._isPaged, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectDown(context.config, context.viewModel, prevColumnSelectData, this._isPaged); } } diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 4a2dc7661c9..06d4b2f5307 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -123,7 +123,7 @@ export class MouseHandler extends ViewEventHandler { e.stopPropagation(); } }; - this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, 'mousewheel', onMouseWheel, true)); + this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel, true)); this._context.addEventHandler(this); } diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 8d69b3dffbf..9a37d512035 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -407,7 +407,12 @@ class HitTestRequest extends BareHitTestRequest { } public fulfill(type: MouseTargetType, position: Position | null = null, range: EditorRange | null = null, detail: any = null): MouseTarget { - return new MouseTarget(this.target, type, this.mouseColumn, position, range, detail); + let mouseColumn = this.mouseColumn; + if (position && position.column < this._ctx.model.getLineMaxColumn(position.lineNumber)) { + // Most likely, the line contains foreign decorations... + mouseColumn = position.column; + } + return new MouseTarget(this.target, type, mouseColumn, position, range, detail); } public withTarget(target: Element | null): HitTestRequest { diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index 640002cbd26..e7494cc7a97 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -24,6 +24,10 @@ import { withNullAsUndefined } from 'vs/base/common/types'; export type ServicesAccessor = ServicesAccessor; export type IEditorContributionCtor = IConstructorSignature1; +export type EditorTelemetryDataFragment = { + target: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + snippet: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; +}; //#region Command @@ -219,16 +223,15 @@ export abstract class EditorAction extends EditorCommand { } protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) { - /* __GDPR__ - "editorActionInvoked" : { - "name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "${include}": [ - "${EditorTelemetryData}" - ] - } - */ - accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id, ...editor.getTelemetryData() }); + type EditorActionInvokedClassification = { + name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + type EditorActionInvokedEvent = { + name: string; + id: string; + }; + accessor.get(ITelemetryService).publicLog2('editorActionInvoked', { name: this.label, id: this.id }); } public abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise; diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index d2389995052..10fb2e1aa6b 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -133,7 +133,7 @@ export class ViewController { public dispatchMouse(data: IMouseDispatchData): void { if (data.middleButton) { if (data.inSelectionMode) { - this._columnSelect(data.position, data.mouseColumn); + this._columnSelect(data.position, data.mouseColumn, true); } else { this.moveTo(data.position); } @@ -182,7 +182,7 @@ export class ViewController { if (this._hasMulticursorModifier(data)) { if (!this._hasNonMulticursorModifier(data)) { if (data.shiftKey) { - this._columnSelect(data.position, data.mouseColumn); + this._columnSelect(data.position, data.mouseColumn, false); } else { // Do multi-cursor operations only when purely alt is pressed if (data.inSelectionMode) { @@ -195,7 +195,7 @@ export class ViewController { } else { if (data.inSelectionMode) { if (data.altKey) { - this._columnSelect(data.position, data.mouseColumn); + this._columnSelect(data.position, data.mouseColumn, true); } else { this._moveToSelect(data.position); } @@ -222,12 +222,13 @@ export class ViewController { this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition)); } - private _columnSelect(viewPosition: Position, mouseColumn: number): void { + private _columnSelect(viewPosition: Position, mouseColumn: number, setAnchorIfNotSet: boolean): void { viewPosition = this._validateViewColumn(viewPosition); this._execMouseCommand(CoreNavigationCommands.ColumnSelect, { position: this._convertViewToModelPosition(viewPosition), viewPosition: viewPosition, - mouseColumn: mouseColumn + mouseColumn: mouseColumn, + setAnchorIfNotSet: setAnchorIfNotSet }); } diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index ac0621d64fb..c275168cca7 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -324,11 +324,6 @@ class Widget { const aboveLeft0 = topLeft.left - ctx.scrollLeft; const belowLeft0 = bottomLeft.left - ctx.scrollLeft; - if (aboveLeft0 < 0 || aboveLeft0 > this._contentWidth) { - // Don't render if position is scrolled outside viewport - return null; - } - let aboveTop = topLeft.top - height; let belowTop = bottomLeft.top + this._lineHeight; let aboveLeft = aboveLeft0 + this._contentLeft; diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index e2397249709..00b684e7ef4 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -12,7 +12,7 @@ import { IStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { IConfiguration } from 'vs/editor/common/editorCommon'; import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; -import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService'; @@ -69,7 +69,7 @@ export class DomReadingContext { export class ViewLineOptions { public readonly themeType: ThemeType; - public readonly renderWhitespace: 'none' | 'boundary' | 'all'; + public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; public readonly renderControlCharacters: boolean; public readonly spaceWidth: number; public readonly useMonospaceOptimizations: boolean; @@ -152,7 +152,7 @@ export class ViewLine implements IVisibleLine { this._options = newOptions; } public onSelectionChanged(): boolean { - if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST) { + if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST || this._options.renderWhitespace === 'selection') { this._isMaybeInvalid = true; return true; } @@ -171,7 +171,9 @@ export class ViewLine implements IVisibleLine { const options = this._options; const actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn); - if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST) { + // Only send selection information when needed for rendering whitespace + let selectionsOnLine: LineRange[] | null = null; + if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST || this._options.renderWhitespace === 'selection') { const selections = viewportData.selections; for (const selection of selections) { @@ -184,7 +186,15 @@ export class ViewLine implements IVisibleLine { const endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn); if (startColumn < endColumn) { - actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular)); + if (this._options.renderWhitespace !== 'selection') { + actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular)); + } else { + if (!selectionsOnLine) { + selectionsOnLine = []; + } + + selectionsOnLine.push(new LineRange(startColumn - 1, endColumn - 1)); + } } } } @@ -204,7 +214,8 @@ export class ViewLine implements IVisibleLine { options.stopRenderingLineAfter, options.renderWhitespace, options.renderControlCharacters, - options.fontLigatures + options.fontLigatures, + selectionsOnLine ); if (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) { diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 8184682f4ae..c883223ae31 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/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 0cd342d195c..c3be18fe35d 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1508,9 +1508,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._codeEditorService.resolveDecorationOptions(typeKey, writable); } - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : {} - */ public getTelemetryData(): { [key: string]: any; } | undefined { return this._telemetryData; } @@ -1851,4 +1848,6 @@ registerThemingParticipant((theme, collector) => { if (unnecessaryBorder) { collector.addRule(`.${SHOW_UNUSED_ENABLED_CLASS} .monaco-editor .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`); } + + collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; }`); }); diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index a285c5af16f..9c3c0df63e8 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -2027,7 +2027,8 @@ class InlineViewZonesComputer extends ViewZonesComputer { config.viewInfo.stopRenderingLineAfter, config.viewInfo.renderWhitespace, config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures + config.viewInfo.fontLigatures, + null // Send no selections, original line cannot be selected ), sb); sb.appendASCIIString(''); diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index beb608e6d74..037883dd530 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -780,7 +780,8 @@ export class DiffReview extends Disposable { config.viewInfo.stopRenderingLineAfter, config.viewInfo.renderWhitespace, config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures + config.viewInfo.fontLigatures, + null )); return r.html; diff --git a/src/vs/editor/browser/widget/media/close-dark.svg b/src/vs/editor/browser/widget/media/close-dark.svg new file mode 100644 index 00000000000..6d16d212ae5 --- /dev/null +++ b/src/vs/editor/browser/widget/media/close-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/close-inverse.svg b/src/vs/editor/browser/widget/media/close-inverse.svg deleted file mode 100644 index 751e89b3b02..00000000000 --- a/src/vs/editor/browser/widget/media/close-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/close-light.svg b/src/vs/editor/browser/widget/media/close-light.svg new file mode 100644 index 00000000000..742fcae4ae7 --- /dev/null +++ b/src/vs/editor/browser/widget/media/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/close.svg b/src/vs/editor/browser/widget/media/close.svg deleted file mode 100644 index fde34404d4e..00000000000 --- a/src/vs/editor/browser/widget/media/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/diffReview.css b/src/vs/editor/browser/widget/media/diffReview.css index edb9317dd80..4cf9f7b83a4 100644 --- a/src/vs/editor/browser/widget/media/diffReview.css +++ b/src/vs/editor/browser/widget/media/diffReview.css @@ -62,9 +62,9 @@ margin: 2px 0; } .monaco-diff-editor .action-label.icon.close-diff-review { - background: url('close.svg') center center no-repeat; + background: url('close-light.svg') center center no-repeat; } .monaco-diff-editor.hc-black .action-label.icon.close-diff-review, .monaco-diff-editor.vs-dark .action-label.icon.close-diff-review { - background: url('close-inverse.svg') center center no-repeat; + background: url('close-dark.svg') center center no-repeat; } \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css index 3266ae96364..fb9e5f5e8b8 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -39,4 +39,10 @@ .monaco-editor .view-overlays { position: absolute; top: 0; -} \ No newline at end of file +} + +/* +.monaco-editor .auto-closed-character { + opacity: 0.3; +} +*/ diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 5866654f0ca..5d1818712b0 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -460,7 +460,7 @@ const editorConfiguration: IConfigurationNode = { 'editor.fastScrollSensitivity': { 'type': 'number', 'default': EDITOR_DEFAULTS.viewInfo.scrollbar.fastScrollSensitivity, - 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed mulitiplier when pressing `Alt`.") + 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") }, 'editor.multiCursorModifier': { 'type': 'string', @@ -696,7 +696,7 @@ const editorConfiguration: IConfigurationNode = { }, 'editor.suggest.filteredTypes': { type: 'object', - default: { keyword: true }, + default: { keyword: true, snippet: true }, markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."), properties: { method: { @@ -901,10 +901,11 @@ const editorConfiguration: IConfigurationNode = { }, 'editor.renderWhitespace': { 'type': 'string', - 'enum': ['none', 'boundary', 'all'], + 'enum': ['none', 'boundary', 'selection', 'all'], 'enumDescriptions': [ '', - nls.localize('renderWhiteSpace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), '' ], default: EDITOR_DEFAULTS.viewInfo.renderWhitespace, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 6c010edc1cf..79ba4dc836d 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -664,7 +664,7 @@ export interface IEditorOptions { * Enable rendering of whitespace. * Defaults to none. */ - renderWhitespace?: 'none' | 'boundary' | 'all'; + renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all'; /** * Enable rendering of control characters. * Defaults to false. @@ -999,7 +999,7 @@ export interface InternalEditorViewOptions { readonly scrollBeyondLastColumn: number; readonly smoothScrolling: boolean; readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'all'; + readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; readonly renderControlCharacters: boolean; readonly fontLigatures: boolean; readonly renderIndentGuides: boolean; @@ -2017,7 +2017,7 @@ export class EditorOptionsValidator { } else if (renderWhitespace === false) { renderWhitespace = 'none'; } - renderWhitespace = _stringSet<'none' | 'boundary' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'all']); + renderWhitespace = _stringSet<'none' | 'boundary' | 'selection' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'selection', 'all']); } let renderLineHighlight = opts.renderLineHighlight; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 81493777b1c..789d3a97b02 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -10,15 +10,16 @@ import { CursorCollection } from 'vs/editor/common/controller/cursorCollection'; import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; -import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; +import { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model'; import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { dispose } from 'vs/base/common/lifecycle'; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -83,6 +84,64 @@ export class CursorModelState { } } +class AutoClosedAction { + + private readonly _model: ITextModel; + + private _autoClosedCharactersDecorations: string[]; + private _autoClosedEnclosingDecorations: string[]; + + constructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) { + this._model = model; + this._autoClosedCharactersDecorations = autoClosedCharactersDecorations; + this._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations; + } + + public dispose(): void { + this._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []); + this._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []); + } + + public getAutoClosedCharactersRanges(): Range[] { + let result: Range[] = []; + for (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]); + if (decorationRange) { + result.push(decorationRange); + } + } + return result; + } + + public isValid(selections: Range[]): boolean { + let enclosingRanges: Range[] = []; + for (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]); + if (decorationRange) { + enclosingRanges.push(decorationRange); + if (decorationRange.startLineNumber !== decorationRange.endLineNumber) { + // Stop tracking if the range becomes multiline... + return false; + } + } + } + enclosingRanges.sort(Range.compareRangesUsingStarts); + + selections.sort(Range.compareRangesUsingStarts); + + for (let i = 0; i < selections.length; i++) { + if (i >= enclosingRanges.length) { + return false; + } + if (!enclosingRanges[i].strictContainsRange(selections[i])) { + return false; + } + } + + return true; + } +} + export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public static MAX_CURSOR_COUNT = 10000; @@ -106,6 +165,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; private _columnSelectData: IColumnSelectData | null; + private _autoClosedActions: AutoClosedAction[]; private _prevEditOperationType: EditOperationType; constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IViewModel) { @@ -120,6 +180,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; this._columnSelectData = null; + this._autoClosedActions = []; this._prevEditOperationType = EditOperationType.Other; this._register(this._model.onDidChangeRawContent((e) => { @@ -173,9 +234,24 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public dispose(): void { this._cursors.dispose(); + this._autoClosedActions = dispose(this._autoClosedActions); super.dispose(); } + private _validateAutoClosedActions(): void { + if (this._autoClosedActions.length > 0) { + let selections: Range[] = this._cursors.getSelections(); + for (let i = 0; i < this._autoClosedActions.length; i++) { + const autoClosedAction = this._autoClosedActions[i]; + if (!autoClosedAction.isValid(selections)) { + autoClosedAction.dispose(); + this._autoClosedActions.splice(i, 1); + i--; + } + } + } + } + // ------ some getters/setters public getPrimaryCursor(): CursorState { @@ -202,6 +278,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.normalize(); this._columnSelectData = null; + this._validateAutoClosedActions(); + this._emitStateChangedIfNecessary(source, reason, oldState); } @@ -296,7 +374,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // a model.setValue() was called this._cursors.dispose(); this._cursors = new CursorCollection(this.context); - + this._validateAutoClosedActions(); this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null); } else { const selectionsFromMarkers = this._cursors.readSelectionFromMarkers(); @@ -314,9 +392,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } const primaryCursor = this._cursors.getPrimaryCursor(); const primaryPos = primaryCursor.viewState.position; + const viewLineNumber = primaryPos.lineNumber; + const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos); return { - toViewLineNumber: primaryPos.lineNumber, - toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos) + isReal: false, + fromViewLineNumber: viewLineNumber, + fromViewVisualColumn: viewVisualColumn, + toViewLineNumber: viewLineNumber, + toViewVisualColumn: viewVisualColumn, }; } @@ -362,6 +445,35 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // The commands were applied correctly this._interpretCommandResult(result); + // Check for auto-closing closed characters + let autoClosedCharactersRanges: IModelDeltaDecoration[] = []; + let autoClosedEnclosingRanges: IModelDeltaDecoration[] = []; + + for (let i = 0; i < opResult.commands.length; i++) { + const command = opResult.commands[i]; + if (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) { + autoClosedCharactersRanges.push({ + range: command.closeCharacterRange, + options: { + inlineClassName: 'auto-closed-character', + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + autoClosedEnclosingRanges.push({ + range: command.enclosingRange, + options: { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + } + } + + if (autoClosedCharactersRanges.length > 0) { + const autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersRanges); + const autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingRanges); + this._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations)); + } + this._prevEditOperationType = opResult.type; } @@ -535,6 +647,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.startTrackingSelections(); } + this._validateAutoClosedActions(); + if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) { this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); } @@ -561,8 +675,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { chr = text.charAt(i); } + let autoClosedCharacters: Range[] = []; + if (this._autoClosedActions.length > 0) { + for (let i = 0, len = this._autoClosedActions.length; i < len; i++) { + autoClosedCharacters = autoClosedCharacters.concat(this._autoClosedActions[i].getAutoClosedCharactersRanges()); + } + } + // Here we must interpret each typed character individually, that's why we create a new context - this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr)); + this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr)); } } else { diff --git a/src/vs/editor/common/controller/cursorColumnSelection.ts b/src/vs/editor/common/controller/cursorColumnSelection.ts index efa35ca08e1..cb89e0efcbd 100644 --- a/src/vs/editor/common/controller/cursorColumnSelection.ts +++ b/src/vs/editor/common/controller/cursorColumnSelection.ts @@ -3,21 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState, IColumnSelectData } from 'vs/editor/common/controller/cursorCommon'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { Selection } from 'vs/editor/common/core/selection'; export interface IColumnSelectResult { viewStates: SingleCursorState[]; reversed: boolean; + fromLineNumber: number; + fromVisualColumn: number; toLineNumber: number; toVisualColumn: number; } export class ColumnSelection { - private static _columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult { + public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult { let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1; let reversed = (fromLineNumber > toLineNumber); let isRTL = (fromVisibleColumn > toVisibleColumn); @@ -61,64 +62,65 @@ export class ColumnSelection { )); } + if (result.length === 0) { + // We are after all the lines, so add cursor at the end of each line + for (let i = 0; i < lineCount; i++) { + const lineNumber = fromLineNumber + (reversed ? -i : i); + const maxColumn = model.getLineMaxColumn(lineNumber); + + result.push(new SingleCursorState( + new Range(lineNumber, maxColumn, lineNumber, maxColumn), 0, + new Position(lineNumber, maxColumn), 0 + )); + } + } + return { viewStates: result, reversed: reversed, + fromLineNumber: fromLineNumber, + fromVisualColumn: fromVisibleColumn, toLineNumber: toLineNumber, toVisualColumn: toVisibleColumn }; } - public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromViewSelection: Selection, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - const fromViewPosition = new Position(fromViewSelection.selectionStartLineNumber, fromViewSelection.selectionStartColumn); - const fromViewVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, fromViewPosition); - return ColumnSelection._columnSelect(config, model, fromViewPosition.lineNumber, fromViewVisibleColumn, toViewLineNumber, toViewVisualColumn); - } - - public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult { + let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn; if (toViewVisualColumn > 1) { toViewVisualColumn--; } - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + return ColumnSelection.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn); } - public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult { let maxVisualViewColumn = 0; - let minViewLineNumber = Math.min(cursor.position.lineNumber, toViewLineNumber); - let maxViewLineNumber = Math.max(cursor.position.lineNumber, toViewLineNumber); + const minViewLineNumber = Math.min(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber); + const maxViewLineNumber = Math.max(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber); for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) { - let lineMaxViewColumn = model.getLineMaxColumn(lineNumber); - let lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn)); + const lineMaxViewColumn = model.getLineMaxColumn(lineNumber); + const lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn)); maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn); } + let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn; if (toViewVisualColumn < maxVisualViewColumn) { toViewVisualColumn++; } - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn); } - public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let linesCount = isPaged ? config.pageSize : 1; - - toViewLineNumber -= linesCount; - if (toViewLineNumber < 1) { - toViewLineNumber = 1; - } - - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult { + const linesCount = isPaged ? config.pageSize : 1; + const toViewLineNumber = Math.max(1, prevColumnSelectData.toViewLineNumber - linesCount); + return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn); } - public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let linesCount = isPaged ? config.pageSize : 1; - - toViewLineNumber += linesCount; - if (toViewLineNumber > model.getLineCount()) { - toViewLineNumber = model.getLineCount(); - } - - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult { + const linesCount = isPaged ? config.pageSize : 1; + const toViewLineNumber = Math.min(model.getLineCount(), prevColumnSelectData.toViewLineNumber + linesCount); + return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn); } } diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index d6a64206ec4..844387516d6 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -21,6 +21,9 @@ import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; export interface IColumnSelectData { + isReal: boolean; + fromViewLineNumber: number; + fromViewVisualColumn: number; toViewLineNumber: number; toViewVisualColumn: number; } diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index c18d081379d..73d984cfb62 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -13,7 +13,7 @@ import { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationT import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { ICommand } from 'vs/editor/common/editorCommon'; +import { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { EnterAction, IndentAction } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; @@ -430,7 +430,7 @@ export class TypeOperations { return null; } - private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean { + private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean { const autoCloseConfig = isQuote(ch) ? config.autoClosingQuotes : config.autoClosingBrackets; if (autoCloseConfig === 'never' || !config.autoClosingPairsClose.hasOwnProperty(ch)) { @@ -461,6 +461,19 @@ export class TypeOperations { return false; } } + + // Must over-type a closing character typed by the editor + let found = false; + for (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) { + const autoClosedCharacter = autoClosedCharacters[j]; + if (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) { + found = true; + break; + } + } + if (!found) { + return false; + } } return true; @@ -573,7 +586,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.autoClosingPairsOpen[ch]; - commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); + commands[i] = new TypeWithAutoClosingCommand(selection, ch, closeCharacter); } return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, @@ -802,7 +815,7 @@ export class TypeOperations { }); } - public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult { + public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult { if (ch === '\n') { let commands: ICommand[] = []; @@ -833,7 +846,7 @@ export class TypeOperations { } } - if (this._isAutoClosingCloseCharType(config, model, selections, ch)) { + if (this._isAutoClosingCloseCharType(config, model, selections, autoClosedCharacters, ch)) { return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch); } @@ -923,3 +936,24 @@ export class TypeOperations { return commands; } } + +export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState { + + private _closeCharacter: string; + public closeCharacterRange: Range | null; + public enclosingRange: Range | null; + + constructor(selection: Selection, openCharacter: string, closeCharacter: string) { + super(selection, openCharacter + closeCharacter, 0, -closeCharacter.length); + this._closeCharacter = closeCharacter; + this.closeCharacterRange = null; + } + + public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection { + let inverseEditOperations = helper.getInverseEditOperations(); + let range = inverseEditOperations[0].range; + this.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn); + this.enclosingRange = range; + return super.computeCursorState(model, helper); + } +} diff --git a/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts index c84b5df9d8a..e212e757dce 100644 --- a/src/vs/editor/common/core/range.ts +++ b/src/vs/editor/common/core/range.ts @@ -126,6 +126,32 @@ export class Range { return true; } + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + public strictContainsRange(range: IRange): boolean { + return Range.strictContainsRange(this, range); + } + + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + public static strictContainsRange(range: IRange, otherRange: IRange): boolean { + if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { + return false; + } + if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { + return false; + } + if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) { + return false; + } + if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) { + return false; + } + return true; + } + /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index 496e77b9ef4..d400024e7c5 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -17,7 +17,8 @@ export const enum ClassName { EditorWarningDecoration = 'squiggly-warning', EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', - EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary' + EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', + EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated' } export const enum NodeColor { diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 9d8464b71cd..e73183b0bcc 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/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index 1b63ef93f9f..ec2bb71ec30 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -545,6 +545,12 @@ export class Searcher { const matchStartIndex = m.index; const matchLength = m[0].length; if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) { + if (matchLength === 0) { + // the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here + // we attempt to recover from that by advancing by one + this._searchRegex.lastIndex += 1; + continue; + } // Exit early if the regex matches the same range twice return null; } diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index f9caed90bae..fa05b9b968c 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/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index a319e8004b6..3da62fed16f 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -221,6 +221,9 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) { inlineClassName = ClassName.EditorUnnecessaryInlineDecoration; } + if (marker.tags.indexOf(MarkerTag.Deprecated) !== -1) { + inlineClassName = ClassName.EditorDeprecatedInlineDecoration; + } } return { diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index df80861b2a8..46d295d2398 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -7,7 +7,8 @@ export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts index 2ee2b7c8831..23d5e072b9d 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/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts index f1b5c0422cb..bbb9b39cb8c 100644 --- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -13,7 +13,8 @@ import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; export const enum RenderWhitespace { None = 0, Boundary = 1, - All = 2 + Selection = 2, + All = 3 } class LinePart { @@ -31,6 +32,28 @@ class LinePart { } } +export class LineRange { + /** + * Zero-based offset on which the range starts, inclusive. + */ + public readonly startOffset: number; + + /** + * Zero-based offset on which the range ends, inclusive. + */ + public readonly endOffset: number; + + constructor(startIndex: number, endIndex: number) { + this.startOffset = startIndex; + this.endOffset = endIndex; + } + + public equals(otherLineRange: LineRange) { + return this.startOffset === otherLineRange.startOffset + && this.endOffset === otherLineRange.endOffset; + } +} + export class RenderLineInput { public readonly useMonospaceOptimizations: boolean; @@ -49,6 +72,12 @@ export class RenderLineInput { public readonly renderControlCharacters: boolean; public readonly fontLigatures: boolean; + /** + * Defined only when renderWhitespace is 'selection'. Selections are non-overlapping, + * and ordered by position within the line. + */ + public readonly selectionsOnLine: LineRange[] | null; + constructor( useMonospaceOptimizations: boolean, canUseHalfwidthRightwardsArrow: boolean, @@ -62,9 +91,10 @@ export class RenderLineInput { tabSize: number, spaceWidth: number, stopRenderingLineAfter: number, - renderWhitespace: 'none' | 'boundary' | 'all', + renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', renderControlCharacters: boolean, - fontLigatures: boolean + fontLigatures: boolean, + selectionsOnLine: LineRange[] | null ) { this.useMonospaceOptimizations = useMonospaceOptimizations; this.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow; @@ -83,10 +113,35 @@ export class RenderLineInput { ? RenderWhitespace.All : renderWhitespace === 'boundary' ? RenderWhitespace.Boundary - : RenderWhitespace.None + : renderWhitespace === 'selection' + ? RenderWhitespace.Selection + : RenderWhitespace.None ); this.renderControlCharacters = renderControlCharacters; this.fontLigatures = fontLigatures; + this.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1); + } + + private sameSelection(otherSelections: LineRange[] | null): boolean { + if (this.selectionsOnLine === null) { + return otherSelections === null; + } + + if (otherSelections === null) { + return false; + } + + if (otherSelections.length !== this.selectionsOnLine.length) { + return false; + } + + for (let i = 0; i < this.selectionsOnLine.length; i++) { + if (!this.selectionsOnLine[i].equals(otherSelections[i])) { + return false; + } + } + + return true; } public equals(other: RenderLineInput): boolean { @@ -106,6 +161,7 @@ export class RenderLineInput { && this.fontLigatures === other.fontLigatures && LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations) && this.lineTokens.equals(other.lineTokens) + && this.sameSelection(other.selectionsOnLine) ); } } @@ -338,8 +394,8 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput } let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len); - if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary) { - tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.renderWhitespace === RenderWhitespace.Boundary); + if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) { + tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.selectionsOnLine, input.renderWhitespace === RenderWhitespace.Boundary); } let containsForeignElements = ForeignElementType.None; if (input.lineDecorations.length > 0) { @@ -481,7 +537,7 @@ function splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces: * Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (→ or ·) do not have the same width as  . * The rendering phase will generate `style="width:..."` for these tokens. */ -function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, onlyBoundary: boolean): LinePart[] { +function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, selections: LineRange[] | null, onlyBoundary: boolean): LinePart[] { let result: LinePart[] = [], resultLen = 0; let tokenIndex = 0; @@ -511,11 +567,17 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW } } tmpIndent = tmpIndent % tabSize; - let wasInWhitespace = false; + let currentSelectionIndex = 0; + let currentSelection = selections && selections[currentSelectionIndex]; for (let charIndex = fauxIndentLength; charIndex < len; charIndex++) { const chCode = lineContent.charCodeAt(charIndex); + if (currentSelection && charIndex >= currentSelection.endOffset) { + currentSelectionIndex++; + currentSelection = selections && selections[currentSelectionIndex]; + } + let isInWhitespace: boolean; if (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) { // in leading or trailing whitespace @@ -540,6 +602,11 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW isInWhitespace = false; } + // If rendering whitespace on selection, check that the charIndex falls within a selection + if (isInWhitespace && selections) { + isInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex; + } + if (wasInWhitespace) { // was in whitespace token if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) { diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 1c889284c76..fe832ef3707 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 e721c4af6cf..5161636aa45 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/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index 102f1b019dc..c0929f47d00 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -148,12 +148,6 @@ class ExecCommandCopyAction extends ExecCommandAction { if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; } - // Prevent copying an empty line by accident - if (editor.getSelections().length === 1 && editor.getSelection().isEmpty()) { - if (editor.getModel().getLineFirstNonWhitespaceColumn(editor.getSelection().positionLineNumber) === 0) { - return; - } - } super.run(accessor, editor); } diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 4484c4405dc..1b76fa157ee 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -80,7 +80,7 @@ export class QuickFixController extends Disposable implements IEditorContributio this._ui.update(newState); } - public showCodeActions(actions: Promise, at: IAnchor | IPosition) { + public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) { return this._ui.showCodeActionList(actions, at); } diff --git a/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts index 8b5bf92538d..a496f3e708f 100644 --- a/src/vs/editor/contrib/codeAction/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/codeActionUi.ts @@ -95,15 +95,7 @@ export class CodeActionUi extends Disposable { } } - public async showCodeActionList(codeActions: Promise, at?: IAnchor | IPosition): Promise { - let actions: CodeActionSet; - try { - actions = await codeActions; - } catch (e) { - onUnexpectedError(e); - return; - } - + public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise { this._codeActionWidget.show(actions, at); } diff --git a/src/vs/editor/contrib/codeAction/lightbulb-autofix-hc.svg b/src/vs/editor/contrib/codeAction/lightbulb-autofix-hc.svg deleted file mode 100644 index 34d4f3aedf6..00000000000 --- a/src/vs/editor/contrib/codeAction/lightbulb-autofix-hc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/codeAction/lightbulb-autofix.svg b/src/vs/editor/contrib/codeAction/lightbulb-autofix.svg deleted file mode 100644 index a4b4858e4dc..00000000000 --- a/src/vs/editor/contrib/codeAction/lightbulb-autofix.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/codeAction/lightbulb-hc.svg b/src/vs/editor/contrib/codeAction/lightbulb-hc.svg deleted file mode 100644 index d2b6e1287a1..00000000000 --- a/src/vs/editor/contrib/codeAction/lightbulb-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/codeAction/lightbulb.svg b/src/vs/editor/contrib/codeAction/lightbulb.svg deleted file mode 100644 index b3596046616..00000000000 --- a/src/vs/editor/contrib/codeAction/lightbulb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css index 2579de84f34..4e312f7dfe6 100644 --- a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css +++ b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css @@ -170,7 +170,7 @@ } .vs-dark .monaco-workbench .symbol-icon.keyword, .hc-black .monaco-workbench .symbol-icon.keyword { - background-image: url('keyword-light.svg'); + background-image: url('keyword-dark.svg'); } /* interface */ diff --git a/src/vs/editor/contrib/documentSymbols/outlineTree.ts b/src/vs/editor/contrib/documentSymbols/outlineTree.ts index 551ff4b4726..a77c8d1bd2e 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineTree.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineTree.ts @@ -13,7 +13,7 @@ import 'vs/css!./media/outlineTree'; import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; import { SymbolKind, symbolKindToCssClass } from 'vs/editor/common/modes'; -import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; +import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -38,7 +38,7 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP export class OutlineIdentityProvider implements IIdentityProvider { - getId(element: TreeElement): { toString(): string; } { + getId(element: OutlineItem): { toString(): string; } { return element.id; } } diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index 3b12e6e1c5d..739cde26fef 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -112,7 +112,8 @@ export class CommonFindController extends Disposable implements editorCommon.IEd searchScope: null, matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, false), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, false), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, false) }, false); if (shouldRestartFind) { @@ -170,13 +171,17 @@ export class CommonFindController extends Disposable implements editorCommon.IEd if (e.matchCase) { this._storageService.store('editor.matchCase', this._state.actualMatchCase, StorageScope.WORKSPACE); } + if (e.preserveCase) { + this._storageService.store('editor.preserveCase', this._state.actualPreserveCase, StorageScope.WORKSPACE); + } } private loadQueryState() { this._state.change({ matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, this._state.matchCase), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, this._state.wholeWord), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, this._state.preserveCase) }, false); } @@ -217,6 +222,11 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } + public togglePreserveCase(): void { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this.highlightFindOptions(); + } + public toggleSearchScope(): void { if (this._state.searchScope) { this._state.change({ searchScope: null }, true); diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 9264aa9b734..1600655f6c3 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -5,7 +5,7 @@ import { RunOnceScheduler, TimeoutTimer } from 'vs/base/common/async'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -59,6 +59,7 @@ export const FIND_IDS = { ToggleWholeWordCommand: 'toggleFindWholeWord', ToggleRegexCommand: 'toggleFindRegex', ToggleSearchScopeCommand: 'toggleFindInSelection', + TogglePreserveCaseCommand: 'togglePreserveCase', ReplaceOneAction: 'editor.action.replaceOne', ReplaceAllAction: 'editor.action.replaceAll', SelectAllMatchesAction: 'editor.action.selectAllMatches' @@ -71,7 +72,7 @@ export class FindModelBoundToEditorModel { private readonly _editor: IActiveCodeEditor; private readonly _state: FindReplaceState; - private _toDispose: IDisposable[]; + private readonly _toDispose = new DisposableStore(); private readonly _decorations: FindDecorations; private _ignoreModelContentChanged: boolean; private readonly _startSearchingTimer: TimeoutTimer; @@ -82,17 +83,16 @@ export class FindModelBoundToEditorModel { constructor(editor: IActiveCodeEditor, state: FindReplaceState) { this._editor = editor; this._state = state; - this._toDispose = []; this._isDisposed = false; this._startSearchingTimer = new TimeoutTimer(); this._decorations = new FindDecorations(editor); - this._toDispose.push(this._decorations); + this._toDispose.add(this._decorations); this._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100); - this._toDispose.push(this._updateDecorationsScheduler); + this._toDispose.add(this._updateDecorationsScheduler); - this._toDispose.push(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + this._toDispose.add(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { if ( e.reason === CursorChangeReason.Explicit || e.reason === CursorChangeReason.Undo @@ -103,7 +103,7 @@ export class FindModelBoundToEditorModel { })); this._ignoreModelContentChanged = false; - this._toDispose.push(this._editor.onDidChangeModelContent((e) => { + this._toDispose.add(this._editor.onDidChangeModelContent((e) => { if (this._ignoreModelContentChanged) { return; } @@ -115,7 +115,7 @@ export class FindModelBoundToEditorModel { this._updateDecorationsScheduler.schedule(); })); - this._toDispose.push(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e))); + this._toDispose.add(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e))); this.research(false, this._state.searchScope); } @@ -123,7 +123,7 @@ export class FindModelBoundToEditorModel { public dispose(): void { this._isDisposed = true; dispose(this._startSearchingTimer); - this._toDispose = dispose(this._toDispose); + this._toDispose.dispose(); } private _onStateChanged(e: FindReplaceStateChangedEvent): void { @@ -417,11 +417,11 @@ export class FindModelBoundToEditorModel { let replacePattern = this._getReplacePattern(); let selection = this._editor.getSelection(); - let nextMatch = this._getNextMatch(selection.getStartPosition(), replacePattern.hasReplacementPatterns, false); + let nextMatch = this._getNextMatch(selection.getStartPosition(), true, false); if (nextMatch) { if (selection.equalsRange(nextMatch.range)) { // selection sits on a find match => replace it! - let replaceString = replacePattern.buildReplaceString(nextMatch.matches); + let replaceString = replacePattern.buildReplaceString(nextMatch.matches, this._state.preserveCase); let command = new ReplaceCommand(selection, replaceString); @@ -483,12 +483,14 @@ export class FindModelBoundToEditorModel { const replacePattern = this._getReplacePattern(); let resultText: string; + const preserveCase = this._state.preserveCase; + if (replacePattern.hasReplacementPatterns) { resultText = modelText.replace(searchRegex, function () { - return replacePattern.buildReplaceString(arguments); + return replacePattern.buildReplaceString(arguments, preserveCase); }); } else { - resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null)); + resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null, preserveCase)); } let command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection()); @@ -502,7 +504,7 @@ export class FindModelBoundToEditorModel { let replaceStrings: string[] = []; for (let i = 0, len = matches.length; i < len; i++) { - replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches); + replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches, this._state.preserveCase); } let command = new ReplaceAllCommand(this._editor.getSelection(), matches.map(m => m.range), replaceStrings); diff --git a/src/vs/editor/contrib/find/findOptionsWidget.ts b/src/vs/editor/contrib/find/findOptionsWidget.ts index 8a61aabd766..76fe78b42de 100644 --- a/src/vs/editor/contrib/find/findOptionsWidget.ts +++ b/src/vs/editor/contrib/find/findOptionsWidget.ts @@ -11,7 +11,7 @@ import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPosit import { FIND_IDS } from 'vs/editor/contrib/find/findModel'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; export class FindOptionsWidget extends Widget implements IOverlayWidget { @@ -47,11 +47,13 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this._domNode.setAttribute('aria-hidden', 'true'); const inputActiveOptionBorderColor = themeService.getTheme().getColor(inputActiveOptionBorder); + const inputActiveOptionBackgroundColor = themeService.getTheme().getColor(inputActiveOptionBackground); this.caseSensitive = this._register(new CaseSensitiveCheckbox({ appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand), isChecked: this._state.matchCase, - inputActiveOptionBorder: inputActiveOptionBorderColor + inputActiveOptionBorder: inputActiveOptionBorderColor, + inputActiveOptionBackground: inputActiveOptionBackgroundColor })); this._domNode.appendChild(this.caseSensitive.domNode); this._register(this.caseSensitive.onChange(() => { @@ -63,7 +65,8 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this.wholeWords = this._register(new WholeWordsCheckbox({ appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand), isChecked: this._state.wholeWord, - inputActiveOptionBorder: inputActiveOptionBorderColor + inputActiveOptionBorder: inputActiveOptionBorderColor, + inputActiveOptionBackground: inputActiveOptionBackgroundColor })); this._domNode.appendChild(this.wholeWords.domNode); this._register(this.wholeWords.onChange(() => { @@ -75,7 +78,8 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this.regex = this._register(new RegexCheckbox({ appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand), isChecked: this._state.isRegex, - inputActiveOptionBorder: inputActiveOptionBorderColor + inputActiveOptionBorder: inputActiveOptionBorderColor, + inputActiveOptionBackground: inputActiveOptionBackgroundColor })); this._domNode.appendChild(this.regex.domNode); this._register(this.regex.onChange(() => { @@ -179,7 +183,10 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { } private _applyTheme(theme: ITheme) { - let inputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder) }; + let inputStyles = { + inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder), + inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground) + }; this.caseSensitive.style(inputStyles); this.wholeWords.style(inputStyles); this.regex.style(inputStyles); diff --git a/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts index 0af1b84cd30..777e273148d 100644 --- a/src/vs/editor/contrib/find/findState.ts +++ b/src/vs/editor/contrib/find/findState.ts @@ -18,6 +18,7 @@ export interface FindReplaceStateChangedEvent { isRegex: boolean; wholeWord: boolean; matchCase: boolean; + preserveCase: boolean; searchScope: boolean; matchesPosition: boolean; matchesCount: boolean; @@ -41,6 +42,8 @@ export interface INewFindReplaceState { wholeWordOverride?: FindOptionOverride; matchCase?: boolean; matchCaseOverride?: FindOptionOverride; + preserveCase?: boolean; + preserveCaseOverride?: FindOptionOverride; searchScope?: Range | null; } @@ -65,11 +68,13 @@ export class FindReplaceState implements IDisposable { private _wholeWordOverride: FindOptionOverride; private _matchCase: boolean; private _matchCaseOverride: FindOptionOverride; + private _preserveCase: boolean; + private _preserveCaseOverride: FindOptionOverride; private _searchScope: Range | null; private _matchesPosition: number; private _matchesCount: number; private _currentMatch: Range | null; - private readonly _onFindReplaceStateChange: Emitter; + private readonly _onFindReplaceStateChange = new Emitter(); public get searchString(): string { return this._searchString; } public get replaceString(): string { return this._replaceString; } @@ -78,16 +83,18 @@ export class FindReplaceState implements IDisposable { public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); } public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); } public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); } + public get preserveCase(): boolean { return effectiveOptionValue(this._preserveCaseOverride, this._preserveCase); } public get actualIsRegex(): boolean { return this._isRegex; } public get actualWholeWord(): boolean { return this._wholeWord; } public get actualMatchCase(): boolean { return this._matchCase; } + public get actualPreserveCase(): boolean { return this._preserveCase; } public get searchScope(): Range | null { return this._searchScope; } public get matchesPosition(): number { return this._matchesPosition; } public get matchesCount(): number { return this._matchesCount; } public get currentMatch(): Range | null { return this._currentMatch; } - public get onFindReplaceStateChange(): Event { return this._onFindReplaceStateChange.event; } + public readonly onFindReplaceStateChange: Event = this._onFindReplaceStateChange.event; constructor() { this._searchString = ''; @@ -100,11 +107,12 @@ export class FindReplaceState implements IDisposable { this._wholeWordOverride = FindOptionOverride.NotSet; this._matchCase = false; this._matchCaseOverride = FindOptionOverride.NotSet; + this._preserveCase = false; + this._preserveCaseOverride = FindOptionOverride.NotSet; this._searchScope = null; this._matchesPosition = 0; this._matchesCount = 0; this._currentMatch = null; - this._onFindReplaceStateChange = new Emitter(); } public dispose(): void { @@ -121,6 +129,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -170,6 +179,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -180,6 +190,7 @@ export class FindReplaceState implements IDisposable { const oldEffectiveIsRegex = this.isRegex; const oldEffectiveWholeWords = this.wholeWord; const oldEffectiveMatchCase = this.matchCase; + const oldEffectivePreserveCase = this.preserveCase; if (typeof newState.searchString !== 'undefined') { if (this._searchString !== newState.searchString) { @@ -218,6 +229,9 @@ export class FindReplaceState implements IDisposable { if (typeof newState.matchCase !== 'undefined') { this._matchCase = newState.matchCase; } + if (typeof newState.preserveCase !== 'undefined') { + this._preserveCase = newState.preserveCase; + } if (typeof newState.searchScope !== 'undefined') { if (!Range.equalsRange(this._searchScope, newState.searchScope)) { this._searchScope = newState.searchScope; @@ -230,6 +244,7 @@ export class FindReplaceState implements IDisposable { this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet); this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet); this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet); + this._preserveCaseOverride = (typeof newState.preserveCaseOverride !== 'undefined' ? newState.preserveCaseOverride : FindOptionOverride.NotSet); if (oldEffectiveIsRegex !== this.isRegex) { somethingChanged = true; @@ -244,6 +259,11 @@ export class FindReplaceState implements IDisposable { changeEvent.matchCase = true; } + if (oldEffectivePreserveCase !== this.preserveCase) { + somethingChanged = true; + changeEvent.preserveCase = true; + } + if (somethingChanged) { this._onFindReplaceStateChange.fire(changeEvent); } diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index 0f2a7720c67..7e1140442ea 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -39,6 +39,11 @@ transition: top 200ms linear; padding: 0 4px; } + +.monaco-editor .find-widget.hiddenEditor { + display: none; +} + /* Find widget when replace is toggled on */ .monaco-editor .find-widget.replaceToggled { top: -74px; /* find input height + replace input height + shadow (10px) */ @@ -79,6 +84,15 @@ height: 25px; } +.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input { + width: 100% !important; + padding-right: 66px; +} + +.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { + padding-right: 22px; +} + .monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input, .monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { padding-top: 2px; @@ -224,12 +238,19 @@ } .monaco-editor .find-widget > .replace-part > .replace-input { + position: relative; display: flex; display: -webkit-flex; vertical-align: middle; width: auto !important; } +.monaco-editor .find-widget > .replace-part > .replace-input > .controls { + position: absolute; + top: 3px; + right: 2px; +} + /* REDUCED */ .monaco-editor .find-widget.reduced-find-widget .matchesCount, .monaco-editor .find-widget.reduced-find-widget .monaco-checkbox { @@ -289,10 +310,6 @@ background-color: rgba(255, 255, 255, 0.1); } -.monaco-editor.vs-dark .find-widget .monaco-checkbox .checkbox:checked + .label { - background-color: rgba(255, 255, 255, 0.1); -} - .monaco-editor.hc-black .find-widget .close-fw, .monaco-editor.vs-dark .find-widget .close-fw { background-image: url('images/close-dark.svg'); diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 5e7febe1ccf..9c9af950e6b 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -13,6 +13,7 @@ import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findIn import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox'; import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash'; import { Widget } from 'vs/base/browser/ui/widget'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { Delayer } from 'vs/base/common/async'; import { Color } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -27,10 +28,11 @@ import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MA import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { alert as alertFn } from 'vs/base/browser/ui/aria/aria'; export interface IFindController { replace(): void; @@ -46,6 +48,7 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind' const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace"); const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace"); +const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case"); const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace"); const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All"); const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode"); @@ -100,6 +103,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _nextBtn: SimpleButton; private _toggleSelectionFind: SimpleCheckbox; private _closeBtn: SimpleButton; + private _preserveCase: Checkbox; private _replaceBtn: SimpleButton; private _replaceAllBtn: SimpleButton; @@ -372,13 +376,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } else { label = NLS_NO_RESULTS; } + this._matchesCount.appendChild(document.createTextNode(label)); + alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString), true); MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth); } // ----- actions + private _getAriaLabel(label: string, currentMatch: Range | null, searchString: string): string { + if (label === NLS_NO_RESULTS) { + return searchString === '' + ? nls.localize('ariaSearchNoResultEmpty', "{0} found", label) + : nls.localize('ariaSearchNoResult', "{0} found for {1}", label, searchString); + } + return currentMatch + ? nls.localize('ariaSearchNoResultWithLineNum', "{0} found for {1} at {2}", label, searchString, currentMatch.startLineNumber + ':' + currentMatch.startColumn) + : nls.localize('ariaSearchNoResultWithLineNumNoCurrentMatch', "{0} found for {1}", label, searchString); + } + /** * If 'selection find' is ON we should not disable the button (its function is to cancel 'selection find'). * If 'selection find' is OFF we enable the button only if there is a selection. @@ -560,6 +577,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _applyTheme(theme: ITheme) { let inputStyles: IFindInputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder), + inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground), inputBackground: theme.getColor(inputBackground), inputForeground: theme.getColor(inputForeground), inputBorder: theme.getColor(inputBorder), @@ -575,14 +593,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas }; this._findInput.style(inputStyles); this._replaceInputBox.style(inputStyles); + this._preserveCase.style(inputStyles); } private _tryUpdateWidgetWidth() { if (!this._isVisible) { return; } - let editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; - let minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; + + const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth; + + if (editorContentWidth <= 0) { + // for example, diff view original editor + dom.addClass(this._domNode, 'hiddenEditor'); + return; + } else if (dom.hasClass(this._domNode, 'hiddenEditor')) { + dom.removeClass(this._domNode, 'hiddenEditor'); + } + + const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; + const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; let collapsedFindWidget = false; let reducedFindWidget = false; let narrowFindWidget = false; @@ -898,6 +928,19 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._state.change({ replaceString: this._replaceInputBox.value }, false); })); + this._preserveCase = this._register(new Checkbox({ + actionClassName: 'monaco-case-sensitive', + title: NLS_PRESERVE_CASE_LABEL, + isChecked: false, + })); + this._preserveCase.checked = !!this._state.preserveCase; + this._register(this._preserveCase.onChange(viaKeyboard => { + if (!viaKeyboard) { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this._replaceInputBox.focus(); + } + })); + // Replace one button this._replaceBtn = this._register(new SimpleButton({ label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction), @@ -922,6 +965,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } })); + let controls = document.createElement('div'); + controls.className = 'controls'; + controls.style.display = 'block'; + controls.appendChild(this._preserveCase.domNode); + replaceInput.appendChild(controls); + let replacePart = document.createElement('div'); replacePart.className = 'replace-part'; replacePart.appendChild(replaceInput); @@ -1217,4 +1266,9 @@ registerThemingParticipant((theme, collector) => { if (inputActiveBorder) { collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { border: 1px solid ${inputActiveBorder.toString()}; }`); } + + const inputActiveBackground = theme.getColor(inputActiveOptionBackground); + if (inputActiveBackground) { + collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { background-color: ${inputActiveBackground.toString()}; }`); + } }); diff --git a/src/vs/editor/contrib/find/images/expando-collapsed-dark.svg b/src/vs/editor/contrib/find/images/expando-collapsed-dark.svg deleted file mode 100644 index 6f3abfce784..00000000000 --- a/src/vs/editor/contrib/find/images/expando-collapsed-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-collapsed.svg b/src/vs/editor/contrib/find/images/expando-collapsed.svg deleted file mode 100644 index 5dcb87c772c..00000000000 --- a/src/vs/editor/contrib/find/images/expando-collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-expanded-dark.svg b/src/vs/editor/contrib/find/images/expando-expanded-dark.svg deleted file mode 100644 index 22dfac04f15..00000000000 --- a/src/vs/editor/contrib/find/images/expando-expanded-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-expanded.svg b/src/vs/editor/contrib/find/images/expando-expanded.svg deleted file mode 100644 index e55ccd923e5..00000000000 --- a/src/vs/editor/contrib/find/images/expando-expanded.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts index 3bd09a78e2d..50e90d7f3ea 100644 --- a/src/vs/editor/contrib/find/replacePattern.ts +++ b/src/vs/editor/contrib/find/replacePattern.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; +import { containsUppercaseCharacter } from 'vs/base/common/strings'; const enum ReplacePatternKind { StaticValue = 0, @@ -48,9 +49,22 @@ export class ReplacePattern { } } - public buildReplaceString(matches: string[] | null): string { + public buildReplaceString(matches: string[] | null, preserveCase?: boolean): string { if (this._state.kind === ReplacePatternKind.StaticValue) { - return this._state.staticValue; + if (preserveCase && matches && (matches[0] !== '')) { + if (matches[0].toUpperCase() === matches[0]) { + return this._state.staticValue.toUpperCase(); + } else if (matches[0].toLowerCase() === matches[0]) { + return this._state.staticValue.toLowerCase(); + } else if (containsUppercaseCharacter(matches[0][0])) { + return this._state.staticValue[0].toUpperCase() + this._state.staticValue.substr(1); + } else { + // we don't understand its pattern yet. + return this._state.staticValue; + } + } else { + return this._state.staticValue; + } } let result = ''; diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 31c75f9f7a6..e3723366157 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -15,7 +15,7 @@ import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBo import { SimpleButton } from 'vs/editor/contrib/find/findWidget'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { editorWidgetBackground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget'; @@ -41,7 +41,8 @@ export abstract class SimpleFindWidget extends Widget { @IContextViewService private readonly _contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService, private readonly _state: FindReplaceState = new FindReplaceState(), - showOptionButtons?: boolean + showOptionButtons?: boolean, + private readonly _invertDefaultDirection: boolean = false ) { super(); @@ -93,13 +94,13 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInput.onKeyDown((e) => { if (e.equals(KeyCode.Enter)) { - this.find(false); + this.find(this._invertDefaultDirection); e.preventDefault(); return; } if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - this.find(true); + this.find(!this._invertDefaultDirection); e.preventDefault(); return; } @@ -180,6 +181,7 @@ export abstract class SimpleFindWidget extends Widget { public updateTheme(theme: ITheme): void { const inputStyles: IFindInputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder), + inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground), inputBackground: theme.getColor(inputBackground), inputForeground: theme.getColor(inputForeground), inputBorder: theme.getColor(inputBorder), @@ -294,4 +296,4 @@ registerThemingParticipant((theme, collector) => { if (widgetShadowColor) { collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts index b36a509e34d..d252ac74c6a 100644 --- a/src/vs/editor/contrib/find/test/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/replacePattern.test.ts @@ -153,4 +153,26 @@ suite('Replace Pattern test', () => { let actual = replacePattern.buildReplaceString(matches); assert.equal(actual, 'a{}'); }); + + test('preserve case', () => { + let replacePattern = parseReplaceString('Def'); + let actual = replacePattern.buildReplaceString(['abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['abc', 'Abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc', 'abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC', 'abc'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['AbC'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['aBC'], true); + assert.equal(actual, 'Def'); + }); }); diff --git a/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts index 70906b653eb..e81b529d061 100644 --- a/src/vs/editor/contrib/folding/foldingModel.ts +++ b/src/vs/editor/contrib/folding/foldingModel.ts @@ -29,9 +29,9 @@ export class FoldingModel { private _isInitialized: boolean; private _updateEventEmitter = new Emitter(); + public readonly onDidChange: Event = this._updateEventEmitter.event; public get regions(): FoldingRegions { return this._regions; } - public get onDidChange(): Event { return this._updateEventEmitter.event; } public get textModel() { return this._textModel; } public get isInitialized() { return this._isInitialized; } diff --git a/src/vs/editor/contrib/gotoError/gotoError.ts b/src/vs/editor/contrib/gotoError/gotoError.ts index 8f1231cbfb8..c16b9be9a6e 100644 --- a/src/vs/editor/contrib/gotoError/gotoError.ts +++ b/src/vs/editor/contrib/gotoError/gotoError.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Emitter } from 'vs/base/common/event'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMarker, IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers'; @@ -32,7 +32,7 @@ class MarkerModel { private readonly _editor: ICodeEditor; private _markers: IMarker[]; private _nextIdx: number; - private _toUnbind: IDisposable[]; + private readonly _toUnbind = new DisposableStore(); private _ignoreSelectionChange: boolean; private readonly _onCurrentMarkerChanged: Emitter; private readonly _onMarkerSetChanged: Emitter; @@ -41,15 +41,14 @@ class MarkerModel { this._editor = editor; this._markers = []; this._nextIdx = -1; - this._toUnbind = []; this._ignoreSelectionChange = false; this._onCurrentMarkerChanged = new Emitter(); this._onMarkerSetChanged = new Emitter(); this.setMarkers(markers); // listen on editor - this._toUnbind.push(this._editor.onDidDispose(() => this.dispose())); - this._toUnbind.push(this._editor.onDidChangeCursorPosition(() => { + this._toUnbind.add(this._editor.onDidDispose(() => this.dispose())); + this._toUnbind.add(this._editor.onDidChangeCursorPosition(() => { if (this._ignoreSelectionChange) { return; } @@ -190,7 +189,7 @@ class MarkerModel { } public dispose(): void { - this._toUnbind = dispose(this._toUnbind); + this._toUnbind.dispose(); } } diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index 80c7a0661c9..7bc5a7fb022 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -13,7 +13,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor, CodeAction } from 'vs/editor/common/modes'; +import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor } from 'vs/editor/common/modes'; import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color'; import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel'; @@ -517,21 +517,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget { const hoverElement = $('div.hover-row.status-bar'); const disposables = new DisposableStore(); const actionsElement = dom.append(hoverElement, $('div.actions')); - disposables.add(this.renderAction(actionsElement, { - label: nls.localize('quick fixes', "Quick Fix..."), - commandId: QuickFixAction.Id, - run: async (target) => { - const codeActionsPromise = this.getCodeActions(markerHover.marker); - disposables.add(toDisposable(() => codeActionsPromise.cancel())); - - const controller = QuickFixController.get(this._editor); - const elementPosition = dom.getDomNodePagePosition(target); - controller.showCodeActions(codeActionsPromise, { - x: elementPosition.left + 6, - y: elementPosition.top + elementPosition.height + 6 - }); - } - })); if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) { disposables.add(this.renderAction(actionsElement, { label: nls.localize('peek problem', "Peek Problem"), @@ -543,27 +528,61 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } })); } + + const quickfixPlaceholderElement = dom.append(actionsElement, $('div')); + quickfixPlaceholderElement.style.opacity = '0'; + quickfixPlaceholderElement.style.transition = 'opacity 0.2s'; + setTimeout(() => quickfixPlaceholderElement.style.opacity = '1', 200); + quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes..."); + disposables.add(toDisposable(() => quickfixPlaceholderElement.remove())); + + + const codeActionsPromise = this.getCodeActions(markerHover.marker); + disposables.add(toDisposable(() => codeActionsPromise.cancel())); + codeActionsPromise.then(actions => { + quickfixPlaceholderElement.style.transition = ''; + quickfixPlaceholderElement.style.opacity = '1'; + + if (!actions.actions.length) { + actions.dispose(); + quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available"); + return; + } + quickfixPlaceholderElement.remove(); + + let showing = false; + disposables.add(toDisposable(() => { + if (!showing) { + actions.dispose(); + } + })); + + disposables.add(this.renderAction(actionsElement, { + label: nls.localize('quick fixes', "Quick Fix..."), + commandId: QuickFixAction.Id, + run: (target) => { + showing = true; + const controller = QuickFixController.get(this._editor); + const elementPosition = dom.getDomNodePagePosition(target); + controller.showCodeActions(actions, { + x: elementPosition.left + 6, + y: elementPosition.top + elementPosition.height + 6 + }); + } + })); + }); + this.renderDisposable.value = disposables; return hoverElement; } private getCodeActions(marker: IMarker): CancelablePromise { - const noAction: CodeAction = { - title: nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), - kind: CodeActionKind.QuickFix.value, - }; - return createCancelablePromise(async (cancellationToken): Promise => { - const result = await getCodeActions( + return createCancelablePromise(cancellationToken => { + return getCodeActions( this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken); - - return { - actions: result.actions.length ? result.actions : [noAction], - hasAutoFix: result.hasAutoFix, - dispose: () => result.dispose(), - }; }); } diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index 051a5378cf0..dc51d0faf45 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -589,13 +589,13 @@ export class AutoIndentOnPaste implements IEditorContribution { private shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean { model.forceTokenization(lineNumber); - let nonWhiteSpaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); - if (nonWhiteSpaceColumn === 0) { + let nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); + if (nonWhitespaceColumn === 0) { return true; } let tokens = model.getLineTokens(lineNumber); if (tokens.getCount() > 0) { - let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhiteSpaceColumn); + let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn); if (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) { return true; } diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index e6984905582..9fb95158f25 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -581,7 +581,7 @@ export class DeleteAllLeftAction extends AbstractDeleteAllToBoundaryAction { return new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn); } } else { - return selection; + return new Range(selection.startLineNumber, 1, selection.endLineNumber, selection.endColumn); } }); diff --git a/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts index 5d2ef4d0515..e9479c0f6d4 100644 --- a/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts @@ -268,7 +268,7 @@ suite('Editor Contrib - Line Operations', () => { editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]); deleteAllLeftAction.run(null!, editor); - assert.equal(model.getLineContent(2), 'ord', '002'); + assert.equal(model.getLineContent(2), 'd', '002'); editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]); deleteAllLeftAction.run(null!, editor); @@ -276,11 +276,11 @@ suite('Editor Contrib - Line Operations', () => { editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]); deleteAllLeftAction.run(null!, editor); - assert.equal(model.getLineContent(4), 'lljour', '004'); + assert.equal(model.getLineContent(4), 'jour', '004'); editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]); deleteAllLeftAction.run(null!, editor); - assert.equal(model.getLineContent(5), 'horlworld', '005'); + assert.equal(model.getLineContent(5), 'world', '005'); }); }); diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index de26df3e3d4..53ea1177390 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -25,79 +25,43 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -const HOVER_MESSAGE_GENERAL_META = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.navigate.mac', "Follow link (cmd + click)") - : nls.localize('links.navigate', "Follow link (ctrl + click)") -); +function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { + const executeCmd = link.url && /^command:/i.test(link.url.toString()); -const HOVER_MESSAGE_COMMAND_META = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.command.mac', "Execute command (cmd + click)") - : nls.localize('links.command', "Execute command (ctrl + click)") -); + const label = link.tooltip + ? link.tooltip + : executeCmd + ? nls.localize('links.navigate.executeCmd', 'Execute command') + : nls.localize('links.navigate.follow', 'Follow link'); -const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.navigate.al.mac', "Follow link (option + click)") - : nls.localize('links.navigate.al', "Follow link (alt + click)") -); + const kb = useMetaKey + ? platform.isMacintosh + ? nls.localize('links.navigate.kb.meta.mac', "cmd + click") + : nls.localize('links.navigate.kb.meta', "ctrl + click") + : platform.isMacintosh + ? nls.localize('links.navigate.kb.alt.mac', "option + click") + : nls.localize('links.navigate.kb.alt', "alt + click"); -const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.command.al.mac', "Execute command (option + click)") - : nls.localize('links.command.al', "Execute command (alt + click)") -); + if (link.url) { + const hoverMessage = new MarkdownString().appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); + hoverMessage.isTrusted = true; + return hoverMessage; + } else { + return new MarkdownString().appendText(`${label} (${kb})`); + } +} const decoration = { - meta: ModelDecorationOptions.register({ + general: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_GENERAL_META + inlineClassName: 'detected-link' }), - metaActive: ModelDecorationOptions.register({ + active: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_GENERAL_META - }), - alt: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_GENERAL_ALT - }), - altActive: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_GENERAL_ALT - }), - altCommand: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_COMMAND_ALT - }), - altCommandActive: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_COMMAND_ALT - }), - metaCommand: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_COMMAND_META - }), - metaCommandActive: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_COMMAND_META - }), + inlineClassName: 'detected-link-active' + }) }; @@ -111,38 +75,11 @@ class LinkOccurrence { } private static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions { - const options = { ...this._getBaseOptions(link, useMetaKey, isActive) }; - if (typeof link.tooltip === 'string') { - const message = new MarkdownString().appendText( - platform.isMacintosh - ? useMetaKey - ? nls.localize('links.custom.mac', "{0} (cmd + click)", link.tooltip) - : nls.localize('links.custom.mac.al', "{0} (option + click)", link.tooltip) - : useMetaKey - ? nls.localize('links.custom', "{0} (ctrl + click)", link.tooltip) - : nls.localize('links.custom.al', "{0} (alt + click)", link.tooltip) - ); - options.hoverMessage = message; - } + const options = { ... (isActive ? decoration.active : decoration.general) }; + options.hoverMessage = getHoverMessage(link, useMetaKey); return options; } - private static _getBaseOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions { - if (link.url && /^command:/i.test(link.url.toString())) { - if (useMetaKey) { - return (isActive ? decoration.metaCommandActive : decoration.metaCommand); - } else { - return (isActive ? decoration.altCommandActive : decoration.altCommand); - } - } else { - if (useMetaKey) { - return (isActive ? decoration.metaActive : decoration.meta); - } else { - return (isActive ? decoration.altActive : decoration.alt); - } - } - } - public decorationId: string; public link: Link; diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-down-hc.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-down-hc.svg deleted file mode 100644 index eca0994a743..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-down-hc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-down-inverse.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-down-inverse.svg deleted file mode 100644 index 0671cba2ff4..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-down-inverse.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-down.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-down.svg deleted file mode 100644 index 9514d8f3172..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-down.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up-hc.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up-hc.svg deleted file mode 100644 index 1c668f52b4c..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up-hc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse-hc.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse-hc.svg deleted file mode 100644 index 1c668f52b4c..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse-hc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse.svg deleted file mode 100644 index 31bdf3deebe..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up.svg deleted file mode 100644 index 7e38887f57d..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/close-inverse.svg b/src/vs/editor/contrib/referenceSearch/media/close-inverse.svg deleted file mode 100644 index 751e89b3b02..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/close-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/referenceSearch/media/close.svg b/src/vs/editor/contrib/referenceSearch/media/close.svg deleted file mode 100644 index fde34404d4e..00000000000 --- a/src/vs/editor/contrib/referenceSearch/media/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/referenceSearch/referenceSearch.ts b/src/vs/editor/contrib/referenceSearch/referenceSearch.ts index 22fb4882f5d..97d8aa5dbf0 100644 --- a/src/vs/editor/contrib/referenceSearch/referenceSearch.ts +++ b/src/vs/editor/contrib/referenceSearch/referenceSearch.ts @@ -27,6 +27,7 @@ import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/c import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { coalesce, flatten } from 'vs/base/common/arrays'; export const defaultReferenceSearchOptions: RequestOptions = { getMetaTitle(model) { @@ -287,15 +288,7 @@ export function provideReferences(model: ITextModel, position: Position, token: }); }); - return Promise.all(promises).then(references => { - let result: Location[] = []; - for (let ref of references) { - if (ref) { - result.push(...ref); - } - } - return result; - }); + return Promise.all(promises).then(references => flatten(coalesce(references))); } registerDefaultLanguageCommand('_executeReferenceProvider', (model, position) => provideReferences(model, position, CancellationToken.None)); diff --git a/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts index a09aa96db74..c24659b44d2 100644 --- a/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -26,6 +26,7 @@ export interface ISnippetInsertOptions { adjustWhitespace: boolean; undoStopBefore: boolean; undoStopAfter: boolean; + clipboardText: string | undefined; } const _defaultOptions: ISnippetInsertOptions = { @@ -34,6 +35,7 @@ const _defaultOptions: ISnippetInsertOptions = { undoStopBefore: true, undoStopAfter: true, adjustWhitespace: true, + clipboardText: undefined }; export class SnippetController2 implements IEditorContribution { diff --git a/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts index 9b9cfe2faff..6140e44858a 100644 --- a/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -320,12 +320,14 @@ export interface ISnippetSessionInsertOptions { overwriteBefore: number; overwriteAfter: number; adjustWhitespace: boolean; + clipboardText: string | undefined; } const _defaultOptions: ISnippetSessionInsertOptions = { overwriteBefore: 0, overwriteAfter: 0, - adjustWhitespace: true + adjustWhitespace: true, + clipboardText: undefined }; export class SnippetSession { @@ -376,7 +378,7 @@ export class SnippetSession { return selection; } - static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } { + static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } { const edits: IIdentifiedSingleEditOperation[] = []; const snippets: OneSnippet[] = []; @@ -385,10 +387,12 @@ export class SnippetSession { } const model = editor.getModel(); - const clipboardService = editor.invokeWithinContext(accessor => accessor.get(IClipboardService, optional)); const workspaceService = editor.invokeWithinContext(accessor => accessor.get(IWorkspaceContextService, optional)); const modelBasedVariableResolver = editor.invokeWithinContext(accessor => new ModelBasedVariableResolver(accessor.get(ILabelService, optional), model)); + const clipboardService = editor.invokeWithinContext(accessor => accessor.get(IClipboardService, optional)); + clipboardText = clipboardText || clipboardService && clipboardService.readTextSync(); + let delta = 0; // know what text the overwrite[Before|After] extensions @@ -440,7 +444,7 @@ export class SnippetSession { snippet.resolveVariables(new CompositeSnippetVariableResolver([ modelBasedVariableResolver, - new ClipboardBasedVariableResolver(clipboardService, idx, indexedSelections.length), + new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length), new SelectionBasedVariableResolver(model, selection), new CommentBasedVariableResolver(model), new TimeBasedVariableResolver, @@ -488,7 +492,7 @@ export class SnippetSession { const model = this._editor.getModel(); // make insert edit and start with first selections - const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace); + const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace, this._options.clipboardText); this._snippets = snippets; const selections = model.pushEditOperations(this._editor.getSelections(), edits, undoEdits => { @@ -507,7 +511,7 @@ export class SnippetSession { return; } this._templateMerges.push([this._snippets[0]._nestingLevel, this._snippets[0]._placeholderGroupsIdx, template]); - const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace); + const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace, options.clipboardText); this._editor.setSelections(this._editor.getModel().pushEditOperations(this._editor.getSelections(), edits, undoEdits => { diff --git a/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts index 42cd74888be..b56f15882dc 100644 --- a/src/vs/editor/contrib/snippet/snippetVariables.ts +++ b/src/vs/editor/contrib/snippet/snippetVariables.ts @@ -11,7 +11,6 @@ import { Selection } from 'vs/editor/common/core/selection'; import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/snippetParser'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { getLeadingWhitespace, commonPrefixLength, isFalsyOrWhitespace, pad, endsWith } from 'vs/base/common/strings'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -128,7 +127,7 @@ export class SelectionBasedVariableResolver implements VariableResolver { export class ModelBasedVariableResolver implements VariableResolver { constructor( - private readonly _labelService: ILabelService, + private readonly _labelService: ILabelService | undefined, private readonly _model: ITextModel ) { // @@ -150,13 +149,13 @@ export class ModelBasedVariableResolver implements VariableResolver { return name.slice(0, idx); } - } else if (name === 'TM_DIRECTORY') { + } else if (name === 'TM_DIRECTORY' && this._labelService) { if (path.dirname(this._model.uri.fsPath) === '.') { return ''; } return this._labelService.getUriLabel(dirname(this._model.uri)); - } else if (name === 'TM_FILEPATH') { + } else if (name === 'TM_FILEPATH' && this._labelService) { return this._labelService.getUriLabel(this._model.uri); } @@ -167,7 +166,7 @@ export class ModelBasedVariableResolver implements VariableResolver { export class ClipboardBasedVariableResolver implements VariableResolver { constructor( - private readonly _clipboardService: IClipboardService | undefined, + private readonly _clipboardText: string | undefined, private readonly _selectionIdx: number, private readonly _selectionCount: number ) { @@ -175,20 +174,19 @@ export class ClipboardBasedVariableResolver implements VariableResolver { } resolve(variable: Variable): string | undefined { - if (variable.name !== 'CLIPBOARD' || !this._clipboardService) { + if (variable.name !== 'CLIPBOARD') { return undefined; } - const text = this._clipboardService.readTextSync(); - if (!text) { + if (!this._clipboardText) { return undefined; } - const lines = text.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); + const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); if (lines.length === this._selectionCount) { return lines[this._selectionIdx]; } else { - return text; + return this._clipboardText; } } } @@ -255,7 +253,7 @@ export class TimeBasedVariableResolver implements VariableResolver { export class WorkspaceBasedVariableResolver implements VariableResolver { constructor( - private readonly _workspaceService: IWorkspaceContextService, + private readonly _workspaceService: IWorkspaceContextService | undefined, ) { // } diff --git a/src/vs/editor/contrib/snippet/test/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts index 2db70286a5b..23122b2b836 100644 --- a/src/vs/editor/contrib/snippet/test/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts @@ -126,7 +126,7 @@ suite('SnippetSession', function () { test('snippets, newline NO whitespace adjust', () => { editor.setSelection(new Selection(2, 5, 2, 5)); - const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', { overwriteBefore: 0, overwriteAfter: 0, adjustWhitespace: false }); + const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', { overwriteBefore: 0, overwriteAfter: 0, adjustWhitespace: false, clipboardText: undefined }); session.insert(); assert.equal(editor.getModel()!.getValue(), 'function foo() {\n abc\n foo\n bar\nconsole.log(a);\n}'); }); @@ -648,7 +648,7 @@ suite('SnippetSession', function () { assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 12))); editor.setSelections([new Selection(1, 9, 1, 12)]); - new SnippetSession(editor, 'far', { overwriteBefore: 3, overwriteAfter: 0, adjustWhitespace: true }).insert(); + new SnippetSession(editor, 'far', { overwriteBefore: 3, overwriteAfter: 0, adjustWhitespace: true, clipboardText: undefined }).insert(); assert.equal(model.getValue(), 'console.far'); }); }); diff --git a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts index abab5967188..7a5367085e7 100644 --- a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts @@ -9,7 +9,6 @@ import { Selection } from 'vs/editor/common/core/selection'; import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver, TimeBasedVariableResolver, WorkspaceBasedVariableResolver } from 'vs/editor/contrib/snippet/snippetVariables'; import { SnippetParser, Variable, VariableResolver } from 'vs/editor/contrib/snippet/snippetParser'; import { TextModel } from 'vs/editor/common/model/textModel'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { Workspace, toWorkspaceFolders, IWorkspace, IWorkspaceContextService, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ILabelService } from 'vs/platform/label/common/label'; import { mock } from 'vs/editor/contrib/suggest/test/suggestModel.test'; @@ -237,65 +236,26 @@ suite('Snippet Variables Resolver', function () { test('Add variable to insert value from clipboard to a snippet #40153', function () { - let readTextResult: string | null | undefined; - const clipboardService = new class implements IClipboardService { - _serviceBrand: any; - readText(): any { return readTextResult; } - readTextSync(): any { return readTextResult; } - _throw = () => { throw new Error(); }; - writeText = this._throw; - readFindText = this._throw; - writeFindText = this._throw; - writeResources = this._throw; - readResources = this._throw; - hasResources = this._throw; - }; - let resolver = new ClipboardBasedVariableResolver(clipboardService, 1, 0); + assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0), 'CLIPBOARD', undefined); - readTextResult = undefined; - assertVariableResolve(resolver, 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0), 'CLIPBOARD', undefined); - readTextResult = null; - assertVariableResolve(resolver, 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0), 'CLIPBOARD', undefined); - readTextResult = ''; - assertVariableResolve(resolver, 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'CLIPBOARD', 'foo'); - readTextResult = 'foo'; - assertVariableResolve(resolver, 'CLIPBOARD', 'foo'); - - assertVariableResolve(resolver, 'foo', undefined); - assertVariableResolve(resolver, 'cLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'foo', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'cLIPBOARD', undefined); }); test('Add variable to insert value from clipboard to a snippet #40153', function () { - let readTextResult: string; - let resolver: VariableResolver; - const clipboardService = new class implements IClipboardService { - _serviceBrand: any; - readText(): string { return readTextResult; } - readTextSync(): any { return readTextResult; } - _throw = () => { throw new Error(); }; - writeText = this._throw; - readFindText = this._throw; - writeFindText = this._throw; - writeResources = this._throw; - readResources = this._throw; - hasResources = this._throw; - }; + assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2), 'CLIPBOARD', 'line1\nline2\nline3'); - resolver = new ClipboardBasedVariableResolver(clipboardService, 1, 2); - readTextResult = 'line1'; - assertVariableResolve(resolver, 'CLIPBOARD', 'line1'); - readTextResult = 'line1\nline2\nline3'; - assertVariableResolve(resolver, 'CLIPBOARD', 'line1\nline2\nline3'); - - readTextResult = 'line1\nline2'; - assertVariableResolve(resolver, 'CLIPBOARD', 'line2'); - readTextResult = 'line1\nline2'; - resolver = new ClipboardBasedVariableResolver(clipboardService, 0, 2); - assertVariableResolve(resolver, 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2), 'CLIPBOARD', 'line2'); + resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2), 'CLIPBOARD', 'line1'); }); diff --git a/src/vs/editor/contrib/suggest/media/Misc_16x.svg b/src/vs/editor/contrib/suggest/media/Misc_16x.svg deleted file mode 100755 index 13ff00b2347..00000000000 --- a/src/vs/editor/contrib/suggest/media/Misc_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Misc_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Misc_inverse_16x.svg deleted file mode 100755 index 50a038657b2..00000000000 --- a/src/vs/editor/contrib/suggest/media/Misc_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/boolean-dark.svg b/src/vs/editor/contrib/suggest/media/boolean-dark.svg deleted file mode 100644 index e009568b131..00000000000 --- a/src/vs/editor/contrib/suggest/media/boolean-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/boolean-light.svg b/src/vs/editor/contrib/suggest/media/boolean-light.svg deleted file mode 100644 index 06613f8bedd..00000000000 --- a/src/vs/editor/contrib/suggest/media/boolean-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/indexer-dark.svg b/src/vs/editor/contrib/suggest/media/indexer-dark.svg deleted file mode 100644 index e92131d3d02..00000000000 --- a/src/vs/editor/contrib/suggest/media/indexer-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/indexer-light.svg b/src/vs/editor/contrib/suggest/media/indexer-light.svg deleted file mode 100644 index 207899642c8..00000000000 --- a/src/vs/editor/contrib/suggest/media/indexer-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/numeric-dark.svg b/src/vs/editor/contrib/suggest/media/numeric-dark.svg deleted file mode 100644 index a1573df0107..00000000000 --- a/src/vs/editor/contrib/suggest/media/numeric-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/numeric-light.svg b/src/vs/editor/contrib/suggest/media/numeric-light.svg deleted file mode 100644 index ea0e56e0225..00000000000 --- a/src/vs/editor/contrib/suggest/media/numeric-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 23f9e36ad30..09594abb493 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -179,7 +179,6 @@ .monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.suggest-icon::before { content: ' '; - background-image: url('Misc_16x.svg'); background-repeat: no-repeat; background-position: center; background-size: 75%; @@ -306,9 +305,6 @@ background-image: url('./info-dark.svg'); } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon::before { background-image: url('Misc_inverse_16x.svg'); } - .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, .monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts index 8a6fca72612..20a7656532a 100644 --- a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts @@ -36,10 +36,17 @@ export class CommitCharacterController { private _onItem(selected: ISelectedSuggestion | undefined): void { if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) { + // no item or no commit characters this.reset(); return; } + if (this._active && this._active.item.item === selected.item) { + // still the same item + return; + } + + // keep item and its commit characters const acceptCharacters = new CharacterSet(); for (const ch of selected.item.completion.commitCharacters) { if (ch.length > 0) { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 9e02b37f673..e6ac05dab25 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -50,7 +50,7 @@ interface ISuggestionTemplateData { iconLabel: IconLabel; typeLabel: HTMLElement; readMore: HTMLElement; - disposables: IDisposable[]; + disposables: DisposableStore; } /** @@ -106,8 +106,7 @@ class Renderer implements IListRenderer renderTemplate(container: HTMLElement): ISuggestionTemplateData { const data = Object.create(null); - const disposables = new DisposableStore(); - data.disposables = [disposables]; + data.disposables = new DisposableStore(); data.root = container; addClass(data.root, 'show-file-icons'); @@ -119,7 +118,7 @@ class Renderer implements IListRenderer const main = append(text, $('.main')); data.iconLabel = new IconLabel(main, { supportHighlights: true }); - disposables.add(data.iconLabel); + data.disposables.add(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); @@ -147,7 +146,7 @@ class Renderer implements IListRenderer configureFont(); - disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo || e.contribInfo) .on(configureFont, null)); @@ -218,7 +217,7 @@ class Renderer implements IListRenderer } disposeTemplate(templateData: ISuggestionTemplateData): void { - templateData.disposables = dispose(templateData.disposables); + templateData.disposables.dispose(); } } @@ -253,7 +252,7 @@ class SuggestionDetails { private type: HTMLElement; private docs: HTMLElement; private ariaLabel: string | null; - private disposables: IDisposable[]; + private readonly disposables: DisposableStore; private renderDisposeable: IDisposable; private borderWidth: number = 1; @@ -264,16 +263,16 @@ class SuggestionDetails { private readonly markdownRenderer: MarkdownRenderer, private readonly triggerKeybindingLabel: string, ) { - this.disposables = []; + this.disposables = new DisposableStore(); this.el = append(container, $('.details')); - this.disposables.push(toDisposable(() => container.removeChild(this.el))); + this.disposables.add(toDisposable(() => container.removeChild(this.el))); this.body = $('.body'); this.scrollbar = new DomScrollableElement(this.body, {}); append(this.el, this.scrollbar.getDomNode()); - this.disposables.push(this.scrollbar); + this.disposables.add(this.scrollbar); this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.close')); @@ -414,7 +413,7 @@ class SuggestionDetails { } dispose(): void { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); this.renderDisposeable = dispose(this.renderDisposeable); } } @@ -672,7 +671,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.list.length < index) { + if (index >= this.list.length || item !== this.list.element(index)) { return; } @@ -689,11 +688,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.focusedItem === item) { - this.currentSuggestionDetails = null; - } - }); + }).catch(onUnexpectedError); } // emit an event @@ -810,12 +805,11 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { assert.deepEqual(actual, EXPECTED); }); + test('cursorWordLeftSelect - issue #74369: cursorWordLeft and cursorWordLeftSelect do not behave consistently', () => { + const EXPECTED = [ + '|this.|is.|a.|test', + ].join('\n'); + const [text,] = deserializePipePositions(EXPECTED); + const actualStops = testRepeatedActionAndExtractPositions( + text, + new Position(1, 15), + ed => cursorWordLeft(ed, true), + ed => ed.getPosition()!, + ed => ed.getPosition()!.equals(new Position(1, 1)) + ); + const actual = serializePipePositions(text, actualStops); + assert.deepEqual(actual, EXPECTED); + }); + test('cursorWordStartLeft', () => { // This is the behaviour observed in Visual Studio, please do not touch test const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n'); diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index 282a4e05ac1..dc4e111f962 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -163,7 +163,7 @@ export class CursorWordLeftSelect extends WordLeftCommand { constructor() { super({ inSelectionMode: true, - wordNavigationType: WordNavigationType.WordStart, + wordNavigationType: WordNavigationType.WordStartFast, id: 'cursorWordLeftSelect', precondition: undefined }); diff --git a/src/vs/editor/standalone/browser/colorizer.ts b/src/vs/editor/standalone/browser/colorizer.ts index ff47bd408c0..d72d141046b 100644 --- a/src/vs/editor/standalone/browser/colorizer.ts +++ b/src/vs/editor/standalone/browser/colorizer.ts @@ -128,7 +128,8 @@ export class Colorizer { -1, 'none', false, - false + false, + null )); return renderResult.html; } @@ -195,7 +196,8 @@ function _fakeColorize(lines: string[], tabSize: number): string { -1, 'none', false, - false + false, + null )); html = html.concat(renderResult.html); @@ -231,7 +233,8 @@ function _actualColorize(lines: string[], tabSize: number, tokenizationSupport: -1, 'none', false, - false + false, + null )); html = html.concat(renderResult.html); diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css index 34cb14546d3..7579f789060 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css @@ -13,12 +13,12 @@ position: absolute; resize: none; overflow: hidden; - background: url('keyboard.svg') center center no-repeat; + background: url('keyboard-light.svg') center center no-repeat; border: 4px solid #F6F6F6; border-radius: 4px; } .monaco-editor.vs-dark .iPadShowKeyboard { - background: url('keyboard-inverse.svg') center center no-repeat; + background: url('keyboard-dark.svg') center center no-repeat; border: 4px solid #252526; } \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg new file mode 100644 index 00000000000..308c5331695 --- /dev/null +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-inverse.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-inverse.svg deleted file mode 100644 index 40bfc47424e..00000000000 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg new file mode 100644 index 00000000000..152bf777f62 --- /dev/null +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard.svg deleted file mode 100644 index bd13224272a..00000000000 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 56a0f094d6e..d333ce03746 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -234,7 +234,9 @@ export class StandaloneCommandService implements ICommandService { private readonly _dynamicCommands: { [id: string]: ICommand; }; private readonly _onWillExecuteCommand = new Emitter(); + private readonly _onDidExecuteCommand = new Emitter(); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; constructor(instantiationService: IInstantiationService) { this._instantiationService = instantiationService; @@ -256,8 +258,10 @@ export class StandaloneCommandService implements ICommandService { } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T; + + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); @@ -352,7 +356,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 996798d3d6a..1777683f5cc 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -47,7 +47,7 @@ import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecora import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; -import { getServices } from 'vs/platform/instantiation/common/extensions'; +import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; export interface IEditorOverrideServices { [index: string]: any; @@ -100,7 +100,7 @@ export module StaticServices { let result = new ServiceCollection(); // make sure to add all services that use `registerSingleton` - for (const { id, descriptor } of getServices()) { + for (const [id, descriptor] of getSingletonServiceDescriptors()) { result.set(id, descriptor); } @@ -140,8 +140,6 @@ export module StaticServices { export const notificationService = define(INotificationService, () => new SimpleNotificationService()); - export const accessibilityService = define(IAccessibilityService, () => new BrowserAccessibilityService()); - export const markerService = define(IMarkerService, () => new MarkerService()); export const modeService = define(IModeService, (o) => new ModeServiceImpl()); @@ -194,6 +192,8 @@ export class DynamicStandaloneServices extends Disposable { let contextKeyService = ensure(IContextKeyService, () => this._register(new ContextKeyService(configurationService))); + ensure(IAccessibilityService, () => new BrowserAccessibilityService(contextKeyService, configurationService)); + ensure(IListService, () => new ListService(contextKeyService)); let commandService = ensure(ICommandService, () => new StandaloneCommandService(this._instantiationService)); diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index aee33dba412..c2a4e4a4560 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -710,7 +710,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(4, 4), viewPosition: new Position(4, 4), - mouseColumn: 15 + mouseColumn: 15, + setAnchorIfNotSet: false }); let expectedSelections = [ @@ -745,7 +746,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(4, 1), viewPosition: new Position(4, 1), - mouseColumn: 1 + mouseColumn: 1, + setAnchorIfNotSet: false }); assertCursor(cursor, [ @@ -784,7 +786,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(1, 1), viewPosition: new Position(1, 1), - mouseColumn: 1 + mouseColumn: 1, + setAnchorIfNotSet: false }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -802,7 +805,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(1, 1), viewPosition: new Position(1, 1), - mouseColumn: 1 + mouseColumn: 1, + setAnchorIfNotSet: false }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -4340,12 +4344,12 @@ suite('autoClosingPairs', () => { let autoClosePositions = [ 'var a |=| [|]|;|', 'var b |=| |`asd`|;|', - 'var c |=| |\'asd!\'|;|', + 'var c |=| |\'asd\'|;|', 'var d |=| |"asd"|;|', 'var e |=| /*3*/| 3;|', 'var f |=| /**| 3 */3;|', 'var g |=| (3+5)|;|', - 'var h |=| {| a:| |\'value!\'| |}|;|', + 'var h |=| {| a:| |\'value\'| |}|;|', ]; for (let i = 0, len = autoClosePositions.length; i < len; i++) { const lineNumber = i + 1; @@ -4490,6 +4494,107 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #37315 - overtypes only those characters that it inserted', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: 'asd' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // overtype! + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // do not overtype! + cursor.setSelections('test', [new Selection(2, 4, 2, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(2), 'y=());'); + + }); + mode.dispose(); + }); + + test('issue #37315 - stops overtyping once cursor leaves area', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 5, 1, 5)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it overtypes only once', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 4, 1, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it can remember multiple auto-closed instances', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: '(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + }); + mode.dispose(); + }); + test('issue #15825: accents on mac US intl keyboard', () => { let mode = new AutoClosingMode(); usingCursor({ diff --git a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts index 96bc4fc047d..92aedce2452 100644 --- a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts +++ b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts @@ -132,7 +132,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from middle', () => { moveTo(thisCursor, 1, 8); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -140,7 +140,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from first non white space character', () => { moveTo(thisCursor, 1, 6); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -148,7 +148,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from first character', () => { moveTo(thisCursor, 1, 1); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -180,7 +180,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from middle', () => { moveTo(thisCursor, 1, 8); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -188,7 +188,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from last non white space character', () => { moveTo(thisCursor, 1, 19); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -196,7 +196,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from line end', () => { moveTo(thisCursor, 1, 21); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -415,7 +415,7 @@ function moveToLineStart(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineStart }); } -function moveToLineFirstNonWhiteSpaceCharacter(cursor: Cursor) { +function moveToLineFirstNonWhitespaceCharacter(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineFirstNonWhitespaceCharacter }); } @@ -427,7 +427,7 @@ function moveToLineEnd(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineEnd }); } -function moveToLineLastNonWhiteSpaceCharacter(cursor: Cursor) { +function moveToLineLastNonWhitespaceCharacter(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineLastNonWhitespaceCharacter }); } diff --git a/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts index 25af3b0efa6..f896360acf4 100644 --- a/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -32,6 +32,9 @@ export class TestCommandService implements ICommandService { private readonly _onWillExecuteCommand = new Emitter(); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + private readonly _onDidExecuteCommand = new Emitter(); + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; + constructor(instantiationService: IInstantiationService) { this._instantiationService = instantiationService; } @@ -43,8 +46,9 @@ export class TestCommandService implements ICommandService { } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T; + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); diff --git a/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts index 3e643742469..eadf902357a 100644 --- a/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -17,6 +17,7 @@ suite('OpenerService', function () { const commandService = new class implements ICommandService { _serviceBrand: any; onWillExecuteCommand = () => ({ dispose: () => { } }); + onDidExecuteCommand = () => ({ dispose: () => { } }); executeCommand(id: string, ...args: any[]): Promise { lastCommand = { id, args }; return Promise.resolve(undefined); diff --git a/src/vs/editor/test/common/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts index 1dc5e82b52c..6476015cb5d 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -733,4 +733,23 @@ suite('TextModelSearch', () => { assert(isMultilineRegexSource('\\n')); assert(isMultilineRegexSource('foo\\W')); }); + + test('issue #74715. \\d* finds empty string and stops searching.', () => { + let model = TextModel.createFromString('10.243.30.10'); + + let searchParams = new SearchParams('\\d*', true, false, null); + + let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100); + assert.deepEqual(actual, [ + new FindMatch(new Range(1, 1, 1, 3), ['10']), + new FindMatch(new Range(1, 3, 1, 3), ['']), + new FindMatch(new Range(1, 4, 1, 7), ['243']), + new FindMatch(new Range(1, 7, 1, 7), ['']), + new FindMatch(new Range(1, 8, 1, 10), ['30']), + new FindMatch(new Range(1, 10, 1, 10), ['']), + new FindMatch(new Range(1, 11, 1, 13), ['10']) + ]); + + model.dispose(); + }); }); diff --git a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts index 0112ef018b6..e3e6ad4c22b 100644 --- a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts @@ -9,7 +9,7 @@ import * as strings from 'vs/base/common/strings'; import { IViewLineTokens } from 'vs/editor/common/core/lineTokens'; import { MetadataConsts } from 'vs/editor/common/modes'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; -import { CharacterMapping, RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { CharacterMapping, RenderLineInput, renderViewLine2 as renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { ViewLineToken, ViewLineTokens } from 'vs/editor/test/common/core/viewLineToken'; @@ -41,7 +41,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expected + ''); @@ -90,7 +91,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expected + ''); @@ -142,7 +144,8 @@ suite('viewLineRenderer.renderLine', () => { 6, 'boundary', false, - false + false, + null )); let expectedOutput = [ @@ -233,7 +236,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'boundary', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -295,7 +299,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -357,7 +362,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -396,7 +402,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -426,7 +433,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(actual.html, '' + expectedOutput.join('') + '', message); } @@ -526,7 +534,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - true + true, + null )); assert.equal(actual.html, '' + expectedOutput.join('') + '', message); } @@ -564,7 +573,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); let expectedOutput = [ 'að ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·ð ®·', @@ -593,7 +603,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(actual.html, '' + expectedOutput.join('') + ''); assert.equal(actual.containsRTL, true); @@ -639,7 +650,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -704,7 +716,7 @@ suite('viewLineRenderer.renderLine', () => { suite('viewLineRenderer.renderLine 2', () => { - function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'all', expected: string): void { + function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', selections: LineRange[] | null, expected: string): void { let actual = renderViewLine(new RenderLineInput( fontIsMonospace, true, @@ -720,7 +732,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, renderWhitespace, false, - false + false, + selections )); assert.deepEqual(actual.html, expected); @@ -745,7 +758,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); let expected = [ @@ -784,7 +798,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); let expected = [ @@ -811,6 +826,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'none', + null, [ '', 'Hello\u00a0world!', @@ -828,6 +844,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'none', + null, [ '', 'Hello\u00a0', @@ -847,6 +864,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u00b7\u00b7\u00b7\u00b7', @@ -868,6 +886,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u00b7\u00b7\u00b7\u00b7', @@ -891,6 +910,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u2192\u00a0\u00a0\u00a0', @@ -913,6 +933,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u00b7\u00b7\u2192\u00a0', @@ -940,6 +961,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 2, 'boundary', + null, [ '', '\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0', @@ -966,6 +988,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 2, 'boundary', + null, [ '', '\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0', @@ -989,6 +1012,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', 'it', @@ -1014,6 +1038,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'all', + null, [ '', '\u00b7', @@ -1027,6 +1052,147 @@ suite('viewLineRenderer.renderLine 2', () => { ); }); + test('createLineParts render whitespace for selection with no selections', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + null, + [ + '', + '\u00a0Hel', + 'lo', + '\u00a0world!\u00a0\u00a0\u00a0', + '', + ].join('') + ); + }); + + test('createLineParts render whitespace for selection with whole line selection', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(0, 14)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00b7', + 'world!', + '\u2192\u00a0\u00a0', + '', + ].join('') + ); + }); + + test('createLineParts render whitespace for selection with selection spanning part of whitespace', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(0, 5)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00a0world!\u00a0\u00a0\u00a0', + '', + ].join('') + ); + }); + + + test('createLineParts render whitespace for selection with multiple selections', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(0, 5), new LineRange(9, 14)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00a0world!', + '\u2192\u00a0\u00a0', + '', + ].join('') + ); + }); + + + test('createLineParts render whitespace for selection with multiple, initially unsorted selections', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(9, 14), new LineRange(0, 5)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00a0world!', + '\u2192\u00a0\u00a0', + '', + ].join('') + ); + }); + + test('createLineParts render whitespace for selection with selections next to each other', () => { + testCreateLineParts( + false, + ' * S', + [ + createPart(4, 0) + ], + 0, + 'selection', + [new LineRange(0, 1), new LineRange(1, 2), new LineRange(2, 3)], + [ + '', + '\u00b7', + '*', + '\u00b7', + 'S', + '', + ].join('') + ); + }); + test('createLineParts can handle unsorted inline decorations', () => { let actual = renderViewLine(new RenderLineInput( false, @@ -1047,7 +1213,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); // 01234567890 @@ -1087,7 +1254,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'all', false, - true + true, + null )); let expected = [ @@ -1119,7 +1287,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'all', false, - true + true, + null )); let expected = [ @@ -1152,7 +1321,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'all', false, - true + true, + null )); let expected = [ @@ -1181,7 +1351,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1214,7 +1385,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1246,7 +1418,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1276,7 +1449,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1305,7 +1479,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'all', false, - false + false, + null )); let expected = [ @@ -1340,7 +1515,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1369,7 +1545,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1400,7 +1577,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1430,7 +1608,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'boundary', false, - false + false, + null )); let expected = [ @@ -1458,7 +1637,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - true + true, + null )); let expected = [ @@ -1490,7 +1670,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - true + true, + null )); let expected = [ @@ -1518,7 +1699,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); return (partIndex: number, partLength: number, offset: number, expected: number) => { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 945d10d7e14..eb2000206ce 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5,6 +5,8 @@ declare namespace monaco { + // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY. + export type Thenable = PromiseLike; export interface IDisposable { @@ -27,7 +29,8 @@ declare namespace monaco { export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { @@ -583,6 +586,14 @@ declare namespace monaco { * Test if `otherRange` is in `range`. If the ranges are equal, will return true. */ static containsRange(range: IRange, otherRange: IRange): boolean; + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + strictContainsRange(range: IRange): boolean; + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + static strictContainsRange(range: IRange, otherRange: IRange): boolean; /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. @@ -3031,7 +3042,7 @@ declare namespace monaco.editor { * Enable rendering of whitespace. * Defaults to none. */ - renderWhitespace?: 'none' | 'boundary' | 'all'; + renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all'; /** * Enable rendering of control characters. * Defaults to false. @@ -3303,7 +3314,7 @@ declare namespace monaco.editor { readonly scrollBeyondLastColumn: number; readonly smoothScrolling: boolean; readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'all'; + readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; readonly renderControlCharacters: boolean; readonly fontLigatures: boolean; readonly renderIndentGuides: boolean; diff --git a/src/vs/platform/accessibility/common/abstractAccessibilityService.ts b/src/vs/platform/accessibility/common/abstractAccessibilityService.ts new file mode 100644 index 00000000000..00710ed605c --- /dev/null +++ b/src/vs/platform/accessibility/common/abstractAccessibilityService.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +export abstract class AbstractAccessibilityService extends Disposable implements IAccessibilityService { + _serviceBrand: any; + + private _accessibilityModeEnabledContext: IContextKey; + protected readonly _onDidChangeAccessibilitySupport = new Emitter(); + readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; + + constructor( + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + ) { + super(); + this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService); + this._register(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.accessibilitySupport')) { + this._updateContextKey(); + } + })); + this._updateContextKey(); + this.onDidChangeAccessibilitySupport(() => this._updateContextKey()); + } + + abstract alwaysUnderlineAccessKeys(): Promise; + abstract getAccessibilitySupport(): AccessibilitySupport; + abstract setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void; + + private _updateContextKey(): void { + const detected = this.getAccessibilitySupport() === AccessibilitySupport.Enabled; + const config = this._configurationService.getValue('editor.accessibilitySupport'); + this._accessibilityModeEnabledContext.set(config === 'on' || (config === 'auto' && detected)); + } +} \ No newline at end of file diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index 72be5a7f6b5..4e695b039f9 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -5,6 +5,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const IAccessibilityService = createDecorator('accessibilityService'); @@ -27,4 +28,6 @@ export const enum AccessibilitySupport { Disabled = 1, Enabled = 2 -} \ No newline at end of file +} + +export const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey('accessibilityModeEnabled', false); diff --git a/src/vs/platform/accessibility/common/accessibilityService.ts b/src/vs/platform/accessibility/common/accessibilityService.ts index 8af1badf8ae..b06cb7eb421 100644 --- a/src/vs/platform/accessibility/common/accessibilityService.ts +++ b/src/vs/platform/accessibility/common/accessibilityService.ts @@ -3,17 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter, Event } from 'vs/base/common/event'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService'; -export class BrowserAccessibilityService extends Disposable implements IAccessibilityService { +export class BrowserAccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { _serviceBrand: any; private _accessibilitySupport = AccessibilitySupport.Unknown; - private readonly _onDidChangeAccessibilitySupport = new Emitter(); - readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; + + constructor( + @IContextKeyService readonly contextKeyService: IContextKeyService, + @IConfigurationService readonly configurationService: IConfigurationService, + ) { + super(contextKeyService, configurationService); + } alwaysUnderlineAccessKeys(): Promise { return Promise.resolve(false); diff --git a/src/vs/platform/browser/contextScopedHistoryWidget.ts b/src/vs/platform/browser/contextScopedHistoryWidget.ts index 94d4de658b5..5e5e8603683 100644 --- a/src/vs/platform/browser/contextScopedHistoryWidget.ts +++ b/src/vs/platform/browser/contextScopedHistoryWidget.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IContextKeyService, ContextKeyDefinedExpr, ContextKeyExpr, ContextKeyAndExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; import { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox'; import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; @@ -66,7 +66,7 @@ export class ContextScopedFindInput extends FindInput { KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'history.showPrevious', weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)), + when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)), primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow], handler: (accessor, arg2) => { @@ -81,7 +81,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'history.showNext', weight: KeybindingWeight.WorkbenchContrib, - when: new ContextKeyAndExpr([new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)]), + when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)), primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow], handler: (accessor, arg2) => { diff --git a/src/vs/platform/clipboard/browser/clipboardService.ts b/src/vs/platform/clipboard/browser/clipboardService.ts new file mode 100644 index 00000000000..9502c4bdc97 --- /dev/null +++ b/src/vs/platform/clipboard/browser/clipboardService.ts @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { URI } from 'vs/base/common/uri'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export class BrowserClipboardService implements IClipboardService { + + _serviceBrand: ServiceIdentifier; + + private _internalResourcesClipboard: URI[] | undefined; + + async writeText(text: string, type?: string): Promise { + return navigator.clipboard.writeText(text); + } + + async readText(type?: string): Promise { + return navigator.clipboard.readText(); + } + + readTextSync(): string | undefined { + return undefined; + } + + readFindText(): string { + // @ts-ignore + return undefined; + } + + writeFindText(text: string): void { } + + writeResources(resources: URI[]): void { + this._internalResourcesClipboard = resources; + } + + readResources(): URI[] { + return this._internalResourcesClipboard || []; + } + + hasResources(): boolean { + return this._internalResourcesClipboard !== undefined && this._internalResourcesClipboard.length > 0; + } +} + +registerSingleton(IClipboardService, BrowserClipboardService, true); \ No newline at end of file diff --git a/src/vs/platform/clipboard/common/clipboardService.ts b/src/vs/platform/clipboard/common/clipboardService.ts index 75ee8724b01..84018111136 100644 --- a/src/vs/platform/clipboard/common/clipboardService.ts +++ b/src/vs/platform/clipboard/common/clipboardService.ts @@ -15,12 +15,12 @@ export interface IClipboardService { /** * Writes text to the system clipboard. */ - writeText(text: string, type?: string): void; + writeText(text: string, type?: string): Promise; /** * Reads the content of the clipboard in plain text */ - readText(type?: string): string; + readText(type?: string): Promise; readTextSync(): string | undefined; diff --git a/src/vs/platform/clipboard/electron-browser/clipboardService.ts b/src/vs/platform/clipboard/electron-browser/clipboardService.ts index 6d000b9da04..4150430af7b 100644 --- a/src/vs/platform/clipboard/electron-browser/clipboardService.ts +++ b/src/vs/platform/clipboard/electron-browser/clipboardService.ts @@ -14,11 +14,11 @@ export class ClipboardService implements IClipboardService { _serviceBrand: any; - writeText(text: string, type?: 'selection' | 'clipboard'): void { + async writeText(text: string, type?: 'selection' | 'clipboard'): Promise { clipboard.writeText(text, type); } - readText(type?: 'selection' | 'clipboard'): string { + async readText(type?: 'selection' | 'clipboard'): Promise { return clipboard.readText(type); } diff --git a/src/vs/platform/commands/common/commands.ts b/src/vs/platform/commands/common/commands.ts index 4777d1ddef7..06c33cf281e 100644 --- a/src/vs/platform/commands/common/commands.ts +++ b/src/vs/platform/commands/common/commands.ts @@ -15,11 +15,13 @@ export const ICommandService = createDecorator('commandService' export interface ICommandEvent { commandId: string; + args: any[]; } export interface ICommandService { _serviceBrand: any; onWillExecuteCommand: Event; + onDidExecuteCommand: Event; executeCommand(commandId: string, ...args: any[]): Promise; } @@ -135,6 +137,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR export const NullCommandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand() { return Promise.resolve(undefined); } diff --git a/src/vs/platform/configuration/test/node/configurationService.test.ts b/src/vs/platform/configuration/test/node/configurationService.test.ts index 22fdbb6c911..ae5e9a795fc 100644 --- a/src/vs/platform/configuration/test/node/configurationService.test.ts +++ b/src/vs/platform/configuration/test/node/configurationService.test.ts @@ -94,7 +94,8 @@ suite('ConfigurationService - Node', () => { const service = new ConfigurationService(URI.file(res.testFile)); await service.initialize(); return new Promise((c, e) => { - service.onDidChangeConfiguration(() => { + const disposable = service.onDidChangeConfiguration(() => { + disposable.dispose(); assert.equal(service.getValue('foo'), 'bar'); service.dispose(); c(); diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 289ba8668ce..8c01c1452d8 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -13,7 +13,9 @@ export const enum ContextKeyExprType { Equals = 3, NotEquals = 4, And = 5, - Regex = 6 + Regex = 6, + NotRegex = 7, + Or = 8 } export interface IContextKeyExprMapper { @@ -27,27 +29,31 @@ export interface IContextKeyExprMapper { export abstract class ContextKeyExpr { public static has(key: string): ContextKeyExpr { - return new ContextKeyDefinedExpr(key); + return ContextKeyDefinedExpr.create(key); } public static equals(key: string, value: any): ContextKeyExpr { - return new ContextKeyEqualsExpr(key, value); + return ContextKeyEqualsExpr.create(key, value); } public static notEquals(key: string, value: any): ContextKeyExpr { - return new ContextKeyNotEqualsExpr(key, value); + return ContextKeyNotEqualsExpr.create(key, value); } public static regex(key: string, value: RegExp): ContextKeyExpr { - return new ContextKeyRegexExpr(key, value); + return ContextKeyRegexExpr.create(key, value); } public static not(key: string): ContextKeyExpr { - return new ContextKeyNotExpr(key); + return ContextKeyNotExpr.create(key); } - public static and(...expr: Array): ContextKeyExpr { - return new ContextKeyAndExpr(expr); + public static and(...expr: Array): ContextKeyExpr | undefined { + return ContextKeyAndExpr.create(expr); + } + + public static or(...expr: Array): ContextKeyExpr | undefined { + return ContextKeyOrExpr.create(expr); } public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | undefined { @@ -55,9 +61,17 @@ export abstract class ContextKeyExpr { return undefined; } + return this._deserializeOrExpression(serialized, strict); + } + + private static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { + let pieces = serialized.split('||'); + return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict))); + } + + private static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { let pieces = serialized.split('&&'); - let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p, strict))); - return result.normalize(); + return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict))); } private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr { @@ -65,24 +79,24 @@ export abstract class ContextKeyExpr { if (serializedOne.indexOf('!=') >= 0) { let pieces = serializedOne.split('!='); - return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('==') >= 0) { let pieces = serializedOne.split('=='); - return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('=~') >= 0) { let pieces = serializedOne.split('=~'); - return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); + return ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); } if (/^\!\s*/.test(serializedOne)) { - return new ContextKeyNotExpr(serializedOne.substr(1).trim()); + return ContextKeyNotExpr.create(serializedOne.substr(1).trim()); } - return new ContextKeyDefinedExpr(serializedOne); + return ContextKeyDefinedExpr.create(serializedOne); } private static _deserializeValue(serializedValue: string, strict: boolean): any { @@ -143,10 +157,10 @@ export abstract class ContextKeyExpr { public abstract getType(): ContextKeyExprType; public abstract equals(other: ContextKeyExpr): boolean; public abstract evaluate(context: IContext): boolean; - public abstract normalize(): ContextKeyExpr | undefined; public abstract serialize(): string; public abstract keys(): string[]; public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr; + public abstract negate(): ContextKeyExpr; } function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { @@ -166,13 +180,21 @@ function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { return (a).cmp(b); case ContextKeyExprType.Regex: return (a).cmp(b); + case ContextKeyExprType.NotRegex: + return (a).cmp(b); + case ContextKeyExprType.And: + return (a).cmp(b); default: throw new Error('Unknown ContextKeyExpr!'); } } export class ContextKeyDefinedExpr implements ContextKeyExpr { - constructor(protected key: string) { + public static create(key: string): ContextKeyExpr { + return new ContextKeyDefinedExpr(key); + } + + protected constructor(protected key: string) { } public getType(): ContextKeyExprType { @@ -200,10 +222,6 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { return (!!context.getValue(this.key)); } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { return this.key; } @@ -215,10 +233,25 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapDefined(this.key); } + + public negate(): ContextKeyExpr { + return ContextKeyNotExpr.create(this.key); + } } export class ContextKeyEqualsExpr implements ContextKeyExpr { - constructor(private readonly key: string, private readonly value: any) { + + public static create(key: string, value: any): ContextKeyExpr { + if (typeof value === 'boolean') { + if (value) { + return ContextKeyDefinedExpr.create(key); + } + return ContextKeyNotExpr.create(key); + } + return new ContextKeyEqualsExpr(key, value); + } + + private constructor(private readonly key: string, private readonly value: any) { } public getType(): ContextKeyExprType { @@ -255,21 +288,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { /* tslint:enable:triple-equals */ } - public normalize(): ContextKeyExpr { - if (typeof this.value === 'boolean') { - if (this.value) { - return new ContextKeyDefinedExpr(this.key); - } - return new ContextKeyNotExpr(this.key); - } - return this; - } - public serialize(): string { - if (typeof this.value === 'boolean') { - return this.normalize().serialize(); - } - return this.key + ' == \'' + this.value + '\''; } @@ -280,10 +299,25 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapEquals(this.key, this.value); } + + public negate(): ContextKeyExpr { + return ContextKeyNotEqualsExpr.create(this.key, this.value); + } } export class ContextKeyNotEqualsExpr implements ContextKeyExpr { - constructor(private key: string, private value: any) { + + public static create(key: string, value: any): ContextKeyExpr { + if (typeof value === 'boolean') { + if (value) { + return ContextKeyNotExpr.create(key); + } + return ContextKeyDefinedExpr.create(key); + } + return new ContextKeyNotEqualsExpr(key, value); + } + + private constructor(private key: string, private value: any) { } public getType(): ContextKeyExprType { @@ -320,21 +354,7 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { /* tslint:enable:triple-equals */ } - public normalize(): ContextKeyExpr { - if (typeof this.value === 'boolean') { - if (this.value) { - return new ContextKeyNotExpr(this.key); - } - return new ContextKeyDefinedExpr(this.key); - } - return this; - } - public serialize(): string { - if (typeof this.value === 'boolean') { - return this.normalize().serialize(); - } - return this.key + ' != \'' + this.value + '\''; } @@ -345,10 +365,19 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapNotEquals(this.key, this.value); } + + public negate(): ContextKeyExpr { + return ContextKeyEqualsExpr.create(this.key, this.value); + } } export class ContextKeyNotExpr implements ContextKeyExpr { - constructor(private key: string) { + + public static create(key: string): ContextKeyExpr { + return new ContextKeyNotExpr(key); + } + + private constructor(private key: string) { } public getType(): ContextKeyExprType { @@ -376,10 +405,6 @@ export class ContextKeyNotExpr implements ContextKeyExpr { return (!context.getValue(this.key)); } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { return '!' + this.key; } @@ -391,11 +416,19 @@ export class ContextKeyNotExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapNot(this.key); } + + public negate(): ContextKeyExpr { + return ContextKeyDefinedExpr.create(this.key); + } } export class ContextKeyRegexExpr implements ContextKeyExpr { - constructor(private key: string, private regexp: RegExp | null) { + public static create(key: string, regexp: RegExp | null): ContextKeyExpr { + return new ContextKeyRegexExpr(key, regexp); + } + + private constructor(private key: string, private regexp: RegExp | null) { // } @@ -435,10 +468,6 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return this.regexp ? this.regexp.test(value) : false; } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { const value = this.regexp ? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}` @@ -450,22 +479,99 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyRegexExpr { return mapFnc.mapRegex(this.key, this.regexp); } + + public negate(): ContextKeyExpr { + return ContextKeyNotRegexExpr.create(this); + } +} + +export class ContextKeyNotRegexExpr implements ContextKeyExpr { + + public static create(actual: ContextKeyRegexExpr): ContextKeyExpr { + return new ContextKeyNotRegexExpr(actual); + } + + private constructor(private readonly _actual: ContextKeyRegexExpr) { + // + } + + public getType(): ContextKeyExprType { + return ContextKeyExprType.NotRegex; + } + + public cmp(other: ContextKeyNotRegexExpr): number { + return this._actual.cmp(other._actual); + } + + public equals(other: ContextKeyExpr): boolean { + if (other instanceof ContextKeyNotRegexExpr) { + return this._actual.equals(other._actual); + } + return false; + } + + public evaluate(context: IContext): boolean { + return !this._actual.evaluate(context); + } + + public serialize(): string { + throw new Error('Method not implemented.'); + } + + public keys(): string[] { + return this._actual.keys(); + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + return new ContextKeyNotRegexExpr(this._actual.map(mapFnc)); + } + + public negate(): ContextKeyExpr { + return this._actual; + } } export class ContextKeyAndExpr implements ContextKeyExpr { - public readonly expr: ContextKeyExpr[]; - constructor(expr: Array) { - this.expr = ContextKeyAndExpr._normalizeArr(expr); + public static create(_expr: Array): ContextKeyExpr | undefined { + const expr = ContextKeyAndExpr._normalizeArr(_expr); + if (expr.length === 0) { + return undefined; + } + + if (expr.length === 1) { + return expr[0]; + } + + return new ContextKeyAndExpr(expr); + } + + private constructor(public readonly expr: ContextKeyExpr[]) { } public getType(): ContextKeyExprType { return ContextKeyExprType.And; } + public cmp(other: ContextKeyAndExpr): number { + if (this.expr.length < other.expr.length) { + return -1; + } + if (this.expr.length > other.expr.length) { + return 1; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + const r = cmp(this.expr[i], other.expr[i]); + if (r !== 0) { + return r; + } + } + return 0; + } + public equals(other: ContextKeyExpr): boolean { if (other instanceof ContextKeyAndExpr) { if (this.expr.length !== other.expr.length) { @@ -500,16 +606,16 @@ export class ContextKeyAndExpr implements ContextKeyExpr { continue; } - e = e.normalize(); - if (!e) { - continue; - } - if (e instanceof ContextKeyAndExpr) { expr = expr.concat(e.expr); continue; } + if (e instanceof ContextKeyOrExpr) { + // Not allowed, because we don't have parens! + throw new Error(`It is not allowed to have an or expression here due to lack of parens!`); + } + expr.push(e); } @@ -519,29 +625,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return expr; } - public normalize(): ContextKeyExpr | undefined { - if (this.expr.length === 0) { - return undefined; - } - - if (this.expr.length === 1) { - return this.expr[0]; - } - - return this; - } - public serialize(): string { - if (this.expr.length === 0) { - return ''; - } - if (this.expr.length === 1) { - const normalized = this.normalize(); - if (!normalized) { - return ''; - } - return normalized.serialize(); - } return this.expr.map(e => e.serialize()).join(' && '); } @@ -556,6 +640,132 @@ export class ContextKeyAndExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc))); } + + public negate(): ContextKeyExpr { + let result: ContextKeyExpr[] = []; + for (let expr of this.expr) { + result.push(expr.negate()); + } + return ContextKeyOrExpr.create(result)!; + } +} + +export class ContextKeyOrExpr implements ContextKeyExpr { + + public static create(_expr: Array): ContextKeyExpr | undefined { + const expr = ContextKeyOrExpr._normalizeArr(_expr); + if (expr.length === 0) { + return undefined; + } + + if (expr.length === 1) { + return expr[0]; + } + + return new ContextKeyOrExpr(expr); + } + + private constructor(public readonly expr: ContextKeyExpr[]) { + } + + public getType(): ContextKeyExprType { + return ContextKeyExprType.Or; + } + + public equals(other: ContextKeyExpr): boolean { + if (other instanceof ContextKeyOrExpr) { + if (this.expr.length !== other.expr.length) { + return false; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + if (!this.expr[i].equals(other.expr[i])) { + return false; + } + } + return true; + } + return false; + } + + public evaluate(context: IContext): boolean { + for (let i = 0, len = this.expr.length; i < len; i++) { + if (this.expr[i].evaluate(context)) { + return true; + } + } + return false; + } + + private static _normalizeArr(arr: Array): ContextKeyExpr[] { + let expr: ContextKeyExpr[] = []; + + if (arr) { + for (let i = 0, len = arr.length; i < len; i++) { + let e: ContextKeyExpr | null | undefined = arr[i]; + if (!e) { + continue; + } + + if (e instanceof ContextKeyOrExpr) { + expr = expr.concat(e.expr); + continue; + } + + expr.push(e); + } + + expr.sort(cmp); + } + + return expr; + } + + public serialize(): string { + return this.expr.map(e => e.serialize()).join(' || '); + } + + public keys(): string[] { + const result: string[] = []; + for (let expr of this.expr) { + result.push(...expr.keys()); + } + return result; + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc))); + } + + public negate(): ContextKeyExpr { + let result: ContextKeyExpr[] = []; + for (let expr of this.expr) { + result.push(expr.negate()); + } + + const terminals = (node: ContextKeyExpr) => { + if (node instanceof ContextKeyOrExpr) { + return node.expr; + } + return [node]; + }; + + // We don't support parens, so here we distribute the AND over the OR terminals + // We always take the first 2 AND pairs and distribute them + while (result.length > 1) { + const LEFT = result.shift()!; + const RIGHT = result.shift()!; + + const all: ContextKeyExpr[] = []; + for (const left of terminals(LEFT)) { + for (const right of terminals(RIGHT)) { + all.push(ContextKeyExpr.and(left, right)!); + } + } + result.unshift(ContextKeyExpr.or(...all)!); + } + + return result[0]; + } } export class RawContextKey extends ContextKeyDefinedExpr { diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index cb12470e3c2..9db3782da31 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -27,7 +27,7 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.notEquals('c2', 'cc2'), ContextKeyExpr.not('d1'), ContextKeyExpr.not('d2') - ); + )!; let b = ContextKeyExpr.and( ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'), @@ -40,7 +40,7 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.has('a1'), ContextKeyExpr.and(ContextKeyExpr.equals('and.a', true)), ContextKeyExpr.not('d2') - ); + )!; assert(a.equals(b), 'expressions should be equal'); }); @@ -50,10 +50,10 @@ suite('ContextKeyExpr', () => { let key1IsFalse = ContextKeyExpr.equals('key1', false); let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true); - assert.ok(key1IsTrue.normalize()!.equals(ContextKeyExpr.has('key1'))); - assert.ok(key1IsNotFalse.normalize()!.equals(ContextKeyExpr.has('key1'))); - assert.ok(key1IsFalse.normalize()!.equals(ContextKeyExpr.not('key1'))); - assert.ok(key1IsNotTrue.normalize()!.equals(ContextKeyExpr.not('key1'))); + assert.ok(key1IsTrue.equals(ContextKeyExpr.has('key1'))); + assert.ok(key1IsNotFalse.equals(ContextKeyExpr.has('key1'))); + assert.ok(key1IsFalse.equals(ContextKeyExpr.not('key1'))); + assert.ok(key1IsNotTrue.equals(ContextKeyExpr.not('key1'))); }); test('evaluate', () => { @@ -93,5 +93,24 @@ suite('ContextKeyExpr', () => { testExpression('a && !b && c == 5', true && !false && '5' == '5'); testExpression('d =~ /e.*/', false); /* tslint:enable:triple-equals */ + + // precedence test: false && true || true === true because && is evaluated first + testExpression('b && a || a', true); + + testExpression('a || b', true); + testExpression('b || b', false); + testExpression('b && a || a && b', false); + }); + + test('negate', () => { + function testNegate(expr: string, expected: string): void { + const actual = ContextKeyExpr.deserialize(expr)!.negate().serialize(); + assert.strictEqual(actual, expected); + } + testNegate('a', '!a'); + testNegate('a && b || c', '!a && !c || !b && !c'); + testNegate('a && b || c || d', '!a && !c && !d || !b && !c && !d'); + testNegate('!a && !b || !c && !d', 'a && c || a && d || b && c || b && d'); + testNegate('!a && !b || !c && !d || !e && !f', 'a && c && e || a && c && f || a && d && e || a && d && f || b && c && e || b && c && f || b && d && e || b && d && f'); }); }); diff --git a/src/vs/platform/contextview/browser/contextMenuService.ts b/src/vs/platform/contextview/browser/contextMenuService.ts index e2fc80ef4ec..bb76d44886a 100644 --- a/src/vs/platform/contextview/browser/contextMenuService.ts +++ b/src/vs/platform/contextview/browser/contextMenuService.ts @@ -17,7 +17,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic _serviceBrand: any; private _onDidContextMenu = this._register(new Emitter()); - get onDidContextMenu(): Event { return this._onDidContextMenu.event; } + readonly onDidContextMenu: Event = this._onDidContextMenu.event; private contextMenuHandler: ContextMenuHandler; 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 00000000000..1304d5cd669 --- /dev/null +++ b/src/vs/platform/debug/common/extensionHostDebugIpc.ts @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. 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'; +import { Disposable } from 'vs/base/common/lifecycle'; + +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 extends Disposable implements IExtensionHostDebugService { + + _serviceBrand: any; + + constructor(private channel: IChannel) { + super(); + } + + 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 b83d063a245..9e74621348c 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts @@ -520,14 +520,21 @@ 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 WorkspaceStatItemClassification = { + name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + count: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WorkspaceStatsClassification = { + fileTypes: WorkspaceStatItemClassification; + configTypes: WorkspaceStatItemClassification; + launchConfigs: WorkspaceStatItemClassification; + }; + 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/download/common/download.ts b/src/vs/platform/download/common/download.ts index 83bd30bdaa5..a012358875d 100644 --- a/src/vs/platform/download/common/download.ts +++ b/src/vs/platform/download/common/download.ts @@ -13,6 +13,6 @@ export interface IDownloadService { _serviceBrand: any; - download(uri: URI, to?: string, cancellationToken?: CancellationToken): Promise; + download(uri: URI, to: URI, cancellationToken?: CancellationToken): Promise; } diff --git a/src/vs/platform/download/common/downloadIpc.ts b/src/vs/platform/download/common/downloadIpc.ts new file mode 100644 index 00000000000..d2d00dd8ccc --- /dev/null +++ b/src/vs/platform/download/common/downloadIpc.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; +import { IDownloadService } from 'vs/platform/download/common/download'; +import { IURITransformer } from 'vs/base/common/uriIpc'; + +export class DownloadServiceChannel implements IServerChannel { + + constructor(private readonly service: IDownloadService) { } + + listen(_: unknown, event: string, arg?: any): Event { + throw new Error('Invalid listen'); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case 'download': return this.service.download(URI.revive(args[0]), URI.revive(args[1])); + } + throw new Error('Invalid call'); + } +} + +export class DownloadServiceChannelClient implements IDownloadService { + + _serviceBrand: any; + + constructor(private channel: IChannel, private getUriTransformer: () => IURITransformer | null) { } + + async download(from: URI, to: URI): Promise { + const uriTransfomer = this.getUriTransformer(); + if (uriTransfomer) { + from = uriTransfomer.transformOutgoingURI(from); + to = uriTransfomer.transformOutgoingURI(to); + } + await this.channel.call('download', [from, to]); + } +} \ No newline at end of file diff --git a/src/vs/platform/download/common/downloadService.ts b/src/vs/platform/download/common/downloadService.ts new file mode 100644 index 00000000000..a2b8365df4c --- /dev/null +++ b/src/vs/platform/download/common/downloadService.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IDownloadService } from 'vs/platform/download/common/download'; +import { URI } from 'vs/base/common/uri'; +import { IRequestService, asText } from 'vs/platform/request/common/request'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IFileService } from 'vs/platform/files/common/files'; +import { Schemas } from 'vs/base/common/network'; + +export class DownloadService implements IDownloadService { + + _serviceBrand: any; + + constructor( + @IRequestService private readonly requestService: IRequestService, + @IFileService private readonly fileService: IFileService + ) { } + + async download(resource: URI, target: URI, cancellationToken: CancellationToken = CancellationToken.None): Promise { + if (resource.scheme === Schemas.file) { + await this.fileService.copy(resource, target); + return; + } + const options = { type: 'GET', url: resource.toString() }; + const context = await this.requestService.request(options, cancellationToken); + if (context.res.statusCode === 200) { + await this.fileService.writeFile(target, context.stream); + } else { + const message = await asText(context); + return Promise.reject(new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`)); + } + } +} diff --git a/src/vs/platform/download/node/downloadIpc.ts b/src/vs/platform/download/node/downloadIpc.ts deleted file mode 100644 index 4bc0593679a..00000000000 --- a/src/vs/platform/download/node/downloadIpc.ts +++ /dev/null @@ -1,76 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URI } from 'vs/base/common/uri'; -import * as path from 'vs/base/common/path'; -import * as fs from 'fs'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Event, Emitter } from 'vs/base/common/event'; -import { IDownloadService } from 'vs/platform/download/common/download'; -import { mkdirp } from 'vs/base/node/pfs'; -import { IURITransformer } from 'vs/base/common/uriIpc'; -import { tmpdir } from 'os'; -import { generateUuid } from 'vs/base/common/uuid'; - -type UploadResponse = Buffer | string | undefined; - -function upload(uri: URI): Event { - const stream = new Emitter(); - const readstream = fs.createReadStream(uri.fsPath); - readstream.on('data', data => stream.fire(data)); - readstream.on('error', error => stream.fire(error.toString())); - readstream.on('close', () => stream.fire(undefined)); - return stream.event; -} - -export class DownloadServiceChannel implements IServerChannel { - - constructor() { } - - listen(_: unknown, event: string, arg?: any): Event { - switch (event) { - case 'upload': return Event.buffer(upload(URI.revive(arg))); - } - - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string): Promise { - throw new Error(`Call not found: ${command}`); - } -} - -export class DownloadServiceChannelClient implements IDownloadService { - - _serviceBrand: any; - - constructor(private channel: IChannel, private getUriTransformer: () => IURITransformer) { } - - download(from: URI, to: string = path.join(tmpdir(), generateUuid())): Promise { - from = this.getUriTransformer().transformOutgoingURI(from); - const dirName = path.dirname(to); - let out: fs.WriteStream; - return new Promise((c, e) => { - return mkdirp(dirName) - .then(() => { - out = fs.createWriteStream(to); - out.once('close', () => c(to)); - out.once('error', e); - const uploadStream = this.channel.listen('upload', from); - const disposable = uploadStream(result => { - if (result === undefined) { - disposable.dispose(); - out.end(() => c(to)); - } else if (Buffer.isBuffer(result)) { - out.write(result); - } else if (typeof result === 'string') { - disposable.dispose(); - out.end(() => e(result)); - } - }); - }); - }); - } -} \ No newline at end of file diff --git a/src/vs/platform/download/node/downloadService.ts b/src/vs/platform/download/node/downloadService.ts deleted file mode 100644 index 7822ed2253d..00000000000 --- a/src/vs/platform/download/node/downloadService.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IDownloadService } from 'vs/platform/download/common/download'; -import { URI } from 'vs/base/common/uri'; -import { Schemas } from 'vs/base/common/network'; -import { copy } from 'vs/base/node/pfs'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { asText, download } from 'vs/base/node/request'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { join } from 'vs/base/common/path'; -import { tmpdir } from 'os'; -import { generateUuid } from 'vs/base/common/uuid'; - -export class DownloadService implements IDownloadService { - - _serviceBrand: any; - - constructor( - @IRequestService private readonly requestService: IRequestService - ) { } - - download(uri: URI, target: string = join(tmpdir(), generateUuid()), cancellationToken: CancellationToken = CancellationToken.None): Promise { - if (uri.scheme === Schemas.file) { - return copy(uri.fsPath, target).then(() => target); - } - const options = { type: 'GET', url: uri.toString() }; - return this.requestService.request(options, cancellationToken) - .then(context => { - if (context.res.statusCode === 200) { - return download(target, context).then(() => target); - } - return asText(context) - .then(message => Promise.reject(new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`))); - }); - } -} diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index d6dc3f659bc..a956739bed7 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -206,7 +206,7 @@ class WindowDriver implements IWindowDriver { throw new Error(`Xterm not found: ${selector}`); } - xterm._core.handler(text); + xterm._core._coreService.triggerDataEvent(text); } async openDevTools(): Promise { diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 3c7468626ae..a6c9eb9d11c 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -47,6 +47,7 @@ export interface ParsedArgs { 'disable-extension'?: string | string[]; 'list-extensions'?: boolean; 'show-versions'?: boolean; + 'category'?: string; 'install-extension'?: string | string[]; 'uninstall-extension'?: string | string[]; 'locate-extension'?: string | string[]; @@ -121,9 +122,6 @@ export interface IEnvironmentService { machineSettingsHome: URI; machineSettingsResource: URI; - settingsSearchBuildId?: number; - settingsSearchUrl?: string; - globalStorageHome: string; workspaceStorageHome: string; @@ -135,7 +133,7 @@ export interface IEnvironmentService { isExtensionDevelopment: boolean; disableExtensions: boolean | string[]; builtinExtensionsPath: string; - extensionsPath: string; + extensionsPath?: string; extensionDevelopmentLocationURI?: URI[]; extensionTestsLocationURI?: URI; @@ -173,4 +171,6 @@ export interface IEnvironmentService { webviewEndpoint?: string; readonly webviewResourceRoot: string; readonly webviewCspSource: string; + + readonly galleryMachineIdResource?: URI; } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 71d6e6cc882..a1d33c98577 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -48,6 +48,7 @@ export const options: Option[] = [ { id: 'extensions-dir', type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, { id: 'list-extensions', type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, { id: 'show-versions', type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, + { id: 'category', type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, { id: 'install-extension', type: 'string', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") }, { id: 'uninstall-extension', type: 'string', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, { id: 'enable-proposed-api', type: 'string', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 0ae144de7ce..e4635b7fc32 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -132,12 +132,6 @@ export class EnvironmentService implements IEnvironmentService { @memoize get workspaceStorageHome(): string { return path.join(this.appSettingsHome.fsPath, 'workspaceStorage'); } - @memoize - get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; } - - @memoize - get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; } - @memoize get keybindingsResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'keybindings.json'); } @@ -272,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/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts similarity index 89% rename from src/vs/platform/extensionManagement/node/extensionGalleryService.ts rename to src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 77ed9973c5d..e291d436115 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -3,26 +3,27 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { tmpdir } from 'os'; -import * as path from 'vs/base/common/path'; import { getErrorMessage, isPromiseCanceledError, canceled } from 'vs/base/common/errors'; import { StatisticType, IGalleryExtension, IExtensionGalleryService, IGalleryExtensionAsset, IQueryOptions, SortBy, SortOrder, IExtensionIdentifier, IReportedExtension, InstallOperation, ITranslation, IGalleryExtensionVersion, IGalleryExtensionAssets, isIExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getGalleryExtensionId, getGalleryExtensionTelemetryData, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { assign, getOrDefault } from 'vs/base/common/objects'; -import { IRequestService } from 'vs/platform/request/node/request'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IPager } from 'vs/base/common/paging'; -import { IRequestOptions, IRequestContext, download, asJson, asText } from 'vs/base/node/request'; -import pkg from 'vs/platform/product/node/package'; -import product from 'vs/platform/product/node/product'; -import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator'; +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 { writeFileSync, readFile } from 'vs/base/node/pfs'; import { generateUuid, isUUID } from 'vs/base/common/uuid'; import { values } from 'vs/base/common/map'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; +import { joinPath } from 'vs/base/common/resources'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { IProductService } from 'vs/platform/product/common/product'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { optional } from 'vs/platform/instantiation/common/instantiation'; interface IRawGalleryExtensionFile { assetType: string; @@ -336,12 +337,15 @@ export class ExtensionGalleryService implements IExtensionGalleryService { @IRequestService private readonly requestService: IRequestService, @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ITelemetryService private readonly telemetryService: ITelemetryService + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IFileService private readonly fileService: IFileService, + @IProductService private readonly productService: IProductService, + @optional(IStorageService) private readonly storageService: IStorageService, ) { - const config = product.extensionsGallery; + const config = productService.extensionsGallery; this.extensionsGalleryUrl = config && config.serviceUrl; this.extensionsControlUrl = config && config.controlUrl; - this.commonHeadersPromise = resolveMarketplaceHeaders(this.environmentService); + this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService, this.storageService); } private api(path = ''): string { @@ -354,7 +358,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { getCompatibleExtension(arg1: IExtensionIdentifier | IGalleryExtension, version?: string): Promise { const extension: IGalleryExtension | null = isIExtensionIdentifier(arg1) ? null : arg1; - if (extension && extension.properties.engine && isEngineValid(extension.properties.engine)) { + if (extension && extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) { return Promise.resolve(extension); } const { id, uuid } = extension ? extension.identifier : arg1; @@ -380,7 +384,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { const versionAsset = rawExtension.versions.filter(v => v.version === version)[0]; if (versionAsset) { const extension = toExtension(rawExtension, versionAsset, 0, query); - if (extension.properties.engine && isEngineValid(extension.properties.engine)) { + if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) { return extension; } } @@ -410,13 +414,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) @@ -533,9 +539,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService { }); } - download(extension: IGalleryExtension, operation: InstallOperation): Promise { + download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise { this.logService.trace('ExtensionGalleryService#download', extension.identifier.id); - const zipPath = path.join(tmpdir(), generateUuid()); + const zip = joinPath(location, generateUuid()); const data = getGalleryExtensionTelemetryData(extension); const startTime = new Date().getTime(); /* __GDPR__ @@ -555,9 +561,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } : extension.assets.download; return this.getAsset(downloadAsset) - .then(context => download(zipPath, context)) + .then(context => this.fileService.writeFile(zip, context.stream)) .then(() => log(new Date().getTime() - startTime)) - .then(() => zipPath); + .then(() => zip); } getReadme(extension: IGalleryExtension, token: CancellationToken): Promise { @@ -613,7 +619,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => { if (galleryExtensions.length) { if (compatible) { - return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine) ? v : null))) + return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine, this.productService.version) ? v : null))) .then(versions => versions .filter(v => !!v) .map(v => ({ version: v!.version, date: v!.lastUpdated }))); @@ -699,7 +705,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { if (!engine) { return null; } - if (isEngineValid(engine)) { + if (isEngineValid(engine, this.productService.version)) { return Promise.resolve(version); } } @@ -731,7 +737,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { const version = versions[0]; return this.getEngine(version) .then(engine => { - if (!isEngineValid(engine)) { + if (!isEngineValid(engine, this.productService.version)) { return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1)); } @@ -772,24 +778,43 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } } -export function resolveMarketplaceHeaders(environmentService: IEnvironmentService): Promise<{ [key: string]: string; }> { - const marketplaceMachineIdFile = path.join(environmentService.userDataPath, 'machineid'); +export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService, storageService?: IStorageService): Promise<{ [key: string]: string; }> { + const headers: IHeaders = { + 'X-Market-Client-Id': `VSCode ${version}`, + '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; + } - return readFile(marketplaceMachineIdFile, 'utf8') - .then(contents => isUUID(contents) ? contents : null, () => null /* error reading ID file */) - .then(uuid => { - if (!uuid) { - uuid = generateUuid(); - try { - writeFileSync(marketplaceMachineIdFile, uuid); - } catch (error) { - //noop - } + if (!uuid) { + uuid = generateUuid(); + try { + await fileService.writeFile(environmentService.galleryMachineIdResource, VSBuffer.fromString(uuid)); + } catch (error) { + //noop } - return { - 'X-Market-Client-Id': `VSCode ${pkg.version}`, - 'User-Agent': `VSCode ${pkg.version}`, - 'X-Market-User-Id': uuid - }; - }); + } + } + + if (storageService) { + uuid = storageService.get('marketplace.userid', StorageScope.GLOBAL) || null; + if (!uuid) { + uuid = generateUuid(); + storageService.store('marketplace.userid', uuid, StorageScope.GLOBAL); + } + } + + if (uuid) { + 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 ad60965cfd1..b075553498d 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'; @@ -151,7 +150,7 @@ export interface IExtensionGalleryService { isEnabled(): boolean; query(token: CancellationToken): Promise>; query(options: IQueryOptions, token: CancellationToken): Promise>; - download(extension: IGalleryExtension, operation: InstallOperation): Promise; + download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise; reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise; getReadme(extension: IGalleryExtension, token: CancellationToken): Promise; getManifest(extension: IGalleryExtension, token: CancellationToken): Promise; @@ -206,110 +205,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 e09049c5b94..70cd46c824a 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'; @@ -35,7 +35,7 @@ import { ExtensionsManifestCache } from 'vs/platform/extensionManagement/node/ex import { ExtensionsLifecycle } from 'vs/platform/extensionManagement/node/extensionLifecycle'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator'; +import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; import { tmpdir } from 'os'; import { generateUuid } from 'vs/base/common/uuid'; import { IDownloadService } from 'vs/platform/download/common/download'; @@ -135,7 +135,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)); @@ -197,7 +197,7 @@ export class ExtensionManagementService extends Disposable implements IExtension .then(manifest => { const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) }; let operation: InstallOperation = InstallOperation.Install; - if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode)) { + if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, pkg.version)) { return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", identifier.id, pkg.version))); } const identifierWithVersion = new ExtensionIdentifierWithVersion(identifier, manifest.version); @@ -241,7 +241,7 @@ export class ExtensionManagementService extends Disposable implements IExtension throw new Error('Download service is not available'); } const downloadedLocation = path.join(tmpdir(), generateUuid()); - return this.downloadService.download(vsix, downloadedLocation).then(() => URI.file(downloadedLocation)); + return this.downloadService.download(vsix, URI.file(downloadedLocation)).then(() => URI.file(downloadedLocation)); } private installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IGalleryMetadata | null, type: ExtensionType, operation: InstallOperation, token: CancellationToken): Promise { @@ -391,9 +391,10 @@ export class ExtensionManagementService extends Disposable implements IExtension }; this.logService.trace('Started downloading extension:', extension.identifier.id); - return this.galleryService.download(extension, operation) + return this.galleryService.download(extension, URI.file(tmpdir()), operation) .then( - zipPath => { + zip => { + const zipPath = zip.fsPath; this.logService.info('Downloaded extension:', extension.identifier.id, zipPath); return getManifest(zipPath) .then( diff --git a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts index f29376fea98..f579807f76c 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts @@ -10,15 +10,32 @@ import { parseArgs } from 'vs/platform/environment/node/argv'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { join } from 'vs/base/common/path'; import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs'; -import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { isUUID } from 'vs/base/common/uuid'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IFileService } from 'vs/platform/files/common/files'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { Schemas } from 'vs/base/common/network'; +import pkg from 'vs/platform/product/node/package'; suite('Extension Gallery Service', () => { const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'extensiongalleryservice'); const marketplaceHome = join(parentDir, 'Marketplace'); + let fileService: IFileService; + let disposables: DisposableStore; setup(done => { + disposables = new DisposableStore(); + fileService = new FileService(new NullLogService()); + disposables.add(fileService); + + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + disposables.add(diskFileSystemProvider); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + // Delete any existing backups completely and then re-create it. rimraf(marketplaceHome, RimRafMode.MOVE).then(() => { mkdirp(marketplaceHome).then(() => { @@ -28,6 +45,7 @@ suite('Extension Gallery Service', () => { }); teardown(done => { + disposables.clear(); rimraf(marketplaceHome, RimRafMode.MOVE).then(done, done); }); @@ -35,10 +53,10 @@ suite('Extension Gallery Service', () => { const args = ['--user-data-dir', marketplaceHome]; const environmentService = new EnvironmentService(parseArgs(args), process.execPath); - return resolveMarketplaceHeaders(environmentService).then(headers => { + return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers => { assert.ok(isUUID(headers['X-Market-User-Id'])); - return resolveMarketplaceHeaders(environmentService).then(headers2 => { + return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers2 => { assert.equal(headers['X-Market-User-Id'], headers2['X-Market-User-Id']); }); }); diff --git a/src/vs/platform/extensions/node/extensionValidator.ts b/src/vs/platform/extensions/common/extensionValidator.ts similarity index 97% rename from src/vs/platform/extensions/node/extensionValidator.ts rename to src/vs/platform/extensions/common/extensionValidator.ts index 3234b2b85db..77f125ff220 100644 --- a/src/vs/platform/extensions/node/extensionValidator.ts +++ b/src/vs/platform/extensions/common/extensionValidator.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import pkg from 'vs/platform/product/node/package'; export interface IParsedVersion { hasCaret: boolean; @@ -222,9 +221,9 @@ export function isValidExtensionVersion(version: string, extensionDesc: IReduced return isVersionValid(version, extensionDesc.engines.vscode, notices); } -export function isEngineValid(engine: string): boolean { +export function isEngineValid(engine: string, version: string): boolean { // TODO@joao: discuss with alex '*' doesn't seem to be a valid engine version - return engine === '*' || isVersionValid(pkg.version, engine); + return engine === '*' || isVersionValid(version, engine); } export function isVersionValid(currentVersion: string, requestedVersion: string, notices: string[] = []): boolean { diff --git a/src/vs/platform/extensions/test/node/extensionValidator.test.ts b/src/vs/platform/extensions/test/node/extensionValidator.test.ts index f88885d9508..860d2201e73 100644 --- a/src/vs/platform/extensions/test/node/extensionValidator.test.ts +++ b/src/vs/platform/extensions/test/node/extensionValidator.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/node/extensionValidator'; +import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/common/extensionValidator'; suite('Extension Version Validator', () => { diff --git a/src/vs/workbench/services/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts similarity index 98% rename from src/vs/workbench/services/files/common/fileService.ts rename to src/vs/platform/files/common/fileService.ts index 67dd28f9bbb..5beb3a1c8b8 100644 --- a/src/vs/workbench/services/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -32,10 +32,10 @@ export class FileService extends Disposable implements IFileService { //#region File System Provider private _onDidChangeFileSystemProviderRegistrations: Emitter = this._register(new Emitter()); - get onDidChangeFileSystemProviderRegistrations(): Event { return this._onDidChangeFileSystemProviderRegistrations.event; } + readonly onDidChangeFileSystemProviderRegistrations: Event = this._onDidChangeFileSystemProviderRegistrations.event; private _onWillActivateFileSystemProvider: Emitter = this._register(new Emitter()); - get onWillActivateFileSystemProvider(): Event { return this._onWillActivateFileSystemProvider.event; } + readonly onWillActivateFileSystemProvider: Event = this._onWillActivateFileSystemProvider.event; private readonly provider = new Map(); @@ -132,10 +132,10 @@ export class FileService extends Disposable implements IFileService { //#endregion private _onAfterOperation: Emitter = this._register(new Emitter()); - get onAfterOperation(): Event { return this._onAfterOperation.event; } + readonly onAfterOperation: Event = this._onAfterOperation.event; private _onError: Emitter = this._register(new Emitter()); - get onError(): Event { return this._onError.event; } + readonly onError: Event = this._onError.event; //#region File Metadata Resolving @@ -763,7 +763,7 @@ export class FileService extends Disposable implements IFileService { //#region File Watching private _onFileChanges: Emitter = this._register(new Emitter()); - get onFileChanges(): Event { return this._onFileChanges.event; } + readonly onFileChanges: Event = this._onFileChanges.event; private activeWatchers = new Map(); diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index adc1bf41767..ad600a2a430 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -6,7 +6,6 @@ import { sep } from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; import * as glob from 'vs/base/common/glob'; -import { isLinux } from 'vs/base/common/platform'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { startsWithIgnoreCase } from 'vs/base/common/strings'; @@ -429,10 +428,10 @@ export class FileChangesEvent { // For deleted also return true when deleted folder is parent of target path if (change.type === FileChangeType.DELETED) { - return isEqualOrParent(resource, change.resource, !isLinux /* ignorecase */); + return isEqualOrParent(resource, change.resource); } - return isEqual(resource, change.resource, !isLinux /* ignorecase */); + return isEqual(resource, change.resource); }); } diff --git a/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts b/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts similarity index 88% rename from src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts rename to src/vs/platform/files/electron-browser/diskFileSystemProvider.ts index 118eb6c762f..2c23af873f1 100644 --- a/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts +++ b/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts @@ -4,19 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { shell } from 'electron'; -import { DiskFileSystemProvider as NodeDiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider as NodeDiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { FileDeleteOptions, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { isWindows } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; import { basename } from 'vs/base/common/path'; -import { ILogService } from 'vs/platform/log/common/log'; export class DiskFileSystemProvider extends NodeDiskFileSystemProvider { - constructor(logService: ILogService) { - super(logService); - } - get capabilities(): FileSystemProviderCapabilities { if (!this._capabilities) { this._capabilities = super.capabilities | FileSystemProviderCapabilities.Trash; diff --git a/src/vs/workbench/services/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts similarity index 92% rename from src/vs/workbench/services/files/node/diskFileSystemProvider.ts rename to src/vs/platform/files/node/diskFileSystemProvider.ts index ef3bb343450..8ef39ec23f0 100644 --- a/src/vs/workbench/services/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -3,25 +3,25 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { mkdir, open, close, read, write, fdatasync } from 'fs'; +import { mkdir, open, close, read, write, fdatasync, Dirent, Stats } from 'fs'; import { promisify } from 'util'; import { IDisposable, Disposable, toDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { isLinux, isWindows } from 'vs/base/common/platform'; -import { statLink, readdir, unlink, move, copy, readFile, truncate, rimraf, RimRafMode, exists } from 'vs/base/node/pfs'; +import { statLink, unlink, move, copy, readFile, truncate, rimraf, RimRafMode, exists, readdirWithFileTypes } from 'vs/base/node/pfs'; import { normalize, basename, dirname } from 'vs/base/common/path'; import { joinPath } from 'vs/base/common/resources'; import { isEqual } from 'vs/base/common/extpath'; import { retry, ThrottledDelayer } from 'vs/base/common/async'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { localize } from 'vs/nls'; -import { IDiskFileChange, toFileChanges, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; -import { FileWatcher as UnixWatcherService } from 'vs/workbench/services/files/node/watcher/unix/watcherService'; -import { FileWatcher as WindowsWatcherService } from 'vs/workbench/services/files/node/watcher/win32/watcherService'; -import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService'; -import { FileWatcher as NodeJSWatcherService } from 'vs/workbench/services/files/node/watcher/nodejs/watcherService'; +import { IDiskFileChange, toFileChanges, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; +import { FileWatcher as UnixWatcherService } from 'vs/platform/files/node/watcher/unix/watcherService'; +import { FileWatcher as WindowsWatcherService } from 'vs/platform/files/node/watcher/win32/watcherService'; +import { FileWatcher as NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/watcherService'; +import { FileWatcher as NodeJSWatcherService } from 'vs/platform/files/node/watcher/nodejs/watcherService'; export interface IWatcherOptions { pollingInterval?: number; @@ -62,15 +62,8 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro try { const { stat, isSymbolicLink } = await statLink(this.toFilePath(resource)); // cannot use fs.stat() here to support links properly - let type: number; - if (isSymbolicLink) { - type = FileType.SymbolicLink | (stat.isDirectory() ? FileType.Directory : FileType.File); - } else { - type = stat.isFile() ? FileType.File : stat.isDirectory() ? FileType.Directory : FileType.Unknown; - } - return { - type, + type: this.toType(stat, isSymbolicLink), ctime: stat.ctime.getTime(), mtime: stat.mtime.getTime(), size: stat.size @@ -82,13 +75,19 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro async readdir(resource: URI): Promise<[string, FileType][]> { try { - const children = await readdir(this.toFilePath(resource)); + const children = await readdirWithFileTypes(this.toFilePath(resource)); const result: [string, FileType][] = []; await Promise.all(children.map(async child => { try { - const stat = await this.stat(joinPath(resource, child)); - result.push([child, stat.type]); + let type: FileType; + if (child.isSymbolicLink()) { + type = (await this.stat(joinPath(resource, child.name))).type; // always resolve target the link points to if any + } else { + type = this.toType(child); + } + + result.push([child.name, type]); } catch (error) { this.logService.trace(error); // ignore errors for individual entries that can arise from permission denied } @@ -100,6 +99,14 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro } } + private toType(entry: Stats | Dirent, isSymbolicLink = entry.isSymbolicLink()): FileType { + if (isSymbolicLink) { + return FileType.SymbolicLink | (entry.isDirectory() ? FileType.Directory : FileType.File); + } + + return entry.isFile() ? FileType.File : entry.isDirectory() ? FileType.Directory : FileType.Unknown; + } + //#endregion //#region File Reading/Writing @@ -360,7 +367,7 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro //#region File Watching private _onDidWatchErrorOccur: Emitter = this._register(new Emitter()); - get onDidErrorOccur(): Event { return this._onDidWatchErrorOccur.event; } + readonly onDidErrorOccur: Event = this._onDidWatchErrorOccur.event; private _onDidChangeFile: Emitter = this._register(new Emitter()); get onDidChangeFile(): Event { return this._onDidChangeFile.event; } diff --git a/src/vs/workbench/services/files/node/watcher/nodejs/watcherService.ts b/src/vs/platform/files/node/watcher/nodejs/watcherService.ts similarity index 98% rename from src/vs/workbench/services/files/node/watcher/nodejs/watcherService.ts rename to src/vs/platform/files/node/watcher/nodejs/watcherService.ts index 4b07ee0a5c0..58c4a327734 100644 --- a/src/vs/workbench/services/files/node/watcher/nodejs/watcherService.ts +++ b/src/vs/platform/files/node/watcher/nodejs/watcherService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; import { Disposable } from 'vs/base/common/lifecycle'; import { statLink } from 'vs/base/node/pfs'; import { realpath } from 'vs/base/node/extpath'; diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts similarity index 98% rename from src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts rename to src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts index 37340c40168..a9db893575b 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService.ts +++ b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts @@ -7,9 +7,9 @@ import * as glob from 'vs/base/common/glob'; import * as extpath from 'vs/base/common/extpath'; import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; -import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; import * as nsfw from 'nsfw'; -import { IWatcherService, IWatcherRequest, IWatcherOptions } from 'vs/workbench/services/files/node/watcher/nsfw/watcher'; +import { IWatcherService, IWatcherRequest, IWatcherOptions } from 'vs/platform/files/node/watcher/nsfw/watcher'; import { ThrottledDelayer } from 'vs/base/common/async'; import { FileChangeType } from 'vs/platform/files/common/files'; import { normalizeNFC } from 'vs/base/common/normalization'; diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts b/src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts similarity index 92% rename from src/vs/workbench/services/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts rename to src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts index 9350b8b9d68..e7c28c9d760 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts +++ b/src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts @@ -6,8 +6,8 @@ import * as assert from 'assert'; import * as platform from 'vs/base/common/platform'; -import { NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService'; -import { IWatcherRequest } from 'vs/workbench/services/files/node/watcher/nsfw/watcher'; +import { NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/nsfwWatcherService'; +import { IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher'; class TestNsfwWatcherService extends NsfwWatcherService { public normalizeRoots(roots: string[]): string[] { diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcher.ts b/src/vs/platform/files/node/watcher/nsfw/watcher.ts similarity index 88% rename from src/vs/workbench/services/files/node/watcher/nsfw/watcher.ts rename to src/vs/platform/files/node/watcher/nsfw/watcher.ts index fa5d4b23335..9ced8b10538 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcher.ts +++ b/src/vs/platform/files/node/watcher/nsfw/watcher.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; export interface IWatcherRequest { path: string; diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherApp.ts b/src/vs/platform/files/node/watcher/nsfw/watcherApp.ts similarity index 74% rename from src/vs/workbench/services/files/node/watcher/nsfw/watcherApp.ts rename to src/vs/platform/files/node/watcher/nsfw/watcherApp.ts index 49c892fb588..69f5da0aa1d 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherApp.ts +++ b/src/vs/platform/files/node/watcher/nsfw/watcherApp.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Server } from 'vs/base/parts/ipc/node/ipc.cp'; -import { WatcherChannel } from 'vs/workbench/services/files/node/watcher/nsfw/watcherIpc'; -import { NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService'; +import { WatcherChannel } from 'vs/platform/files/node/watcher/nsfw/watcherIpc'; +import { NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/nsfwWatcherService'; const server = new Server('watcher'); const service = new NsfwWatcherService(); diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherIpc.ts b/src/vs/platform/files/node/watcher/nsfw/watcherIpc.ts similarity index 94% rename from src/vs/workbench/services/files/node/watcher/nsfw/watcherIpc.ts rename to src/vs/platform/files/node/watcher/nsfw/watcherIpc.ts index 7e1d5edd7e1..72841ad037c 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherIpc.ts +++ b/src/vs/platform/files/node/watcher/nsfw/watcherIpc.ts @@ -6,7 +6,7 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IWatcherRequest, IWatcherService, IWatcherOptions } from './watcher'; import { Event } from 'vs/base/common/event'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; export class WatcherChannel implements IServerChannel { diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts b/src/vs/platform/files/node/watcher/nsfw/watcherService.ts similarity index 89% rename from src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts rename to src/vs/platform/files/node/watcher/nsfw/watcherService.ts index dd4d542ccb6..8b4673d1934 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts +++ b/src/vs/platform/files/node/watcher/nsfw/watcherService.ts @@ -5,10 +5,10 @@ import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; -import { WatcherChannelClient } from 'vs/workbench/services/files/node/watcher/nsfw/watcherIpc'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; +import { WatcherChannelClient } from 'vs/platform/files/node/watcher/nsfw/watcherIpc'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IWatcherRequest } from 'vs/workbench/services/files/node/watcher/nsfw/watcher'; +import { IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher'; import { getPathFromAmdModule } from 'vs/base/common/amd'; export class FileWatcher extends Disposable { @@ -39,7 +39,7 @@ export class FileWatcher extends Disposable { serverName: 'File Watcher (nsfw)', args: ['--type=watcherService'], env: { - AMD_ENTRYPOINT: 'vs/workbench/services/files/node/watcher/nsfw/watcherApp', + AMD_ENTRYPOINT: 'vs/platform/files/node/watcher/nsfw/watcherApp', PIPE_LOGGING: 'true', VERBOSE_LOGGING: 'true' // transmit console logs from server to client } diff --git a/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts similarity index 99% rename from src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts rename to src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts index b88f36e4512..a03e76ba178 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts +++ b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts @@ -14,8 +14,8 @@ import { ThrottledDelayer } from 'vs/base/common/async'; import { normalizeNFC } from 'vs/base/common/normalization'; import { realcaseSync } from 'vs/base/node/extpath'; import { isMacintosh, isLinux } from 'vs/base/common/platform'; -import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; -import { IWatcherRequest, IWatcherService, IWatcherOptions } from 'vs/workbench/services/files/node/watcher/unix/watcher'; +import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; +import { IWatcherRequest, IWatcherService, IWatcherOptions } from 'vs/platform/files/node/watcher/unix/watcher'; import { Emitter, Event } from 'vs/base/common/event'; interface IWatcher { diff --git a/src/vs/workbench/services/files/node/watcher/unix/test/chockidarWatcherService.test.ts b/src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts similarity index 99% rename from src/vs/workbench/services/files/node/watcher/unix/test/chockidarWatcherService.test.ts rename to src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts index 974169f5148..45b05c95ed4 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/test/chockidarWatcherService.test.ts +++ b/src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts @@ -11,7 +11,7 @@ import { normalizeRoots, ChokidarWatcherService } from '../chokidarWatcherServic import { IWatcherRequest } from '../watcher'; import * as platform from 'vs/base/common/platform'; import { Delayer } from 'vs/base/common/async'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange } from 'vs/platform/files/node/watcher/watcher'; import { FileChangeType } from 'vs/platform/files/common/files'; function newRequest(basePath: string, ignored: string[] = []): IWatcherRequest { diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcher.ts b/src/vs/platform/files/node/watcher/unix/watcher.ts similarity index 89% rename from src/vs/workbench/services/files/node/watcher/unix/watcher.ts rename to src/vs/platform/files/node/watcher/unix/watcher.ts index fc87e15803a..158f1e5fc21 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcher.ts +++ b/src/vs/platform/files/node/watcher/unix/watcher.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; export interface IWatcherRequest { path: string; diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherApp.ts b/src/vs/platform/files/node/watcher/unix/watcherApp.ts similarity index 74% rename from src/vs/workbench/services/files/node/watcher/unix/watcherApp.ts rename to src/vs/platform/files/node/watcher/unix/watcherApp.ts index 01473fb5c88..c921518118f 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherApp.ts +++ b/src/vs/platform/files/node/watcher/unix/watcherApp.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Server } from 'vs/base/parts/ipc/node/ipc.cp'; -import { WatcherChannel } from 'vs/workbench/services/files/node/watcher/unix/watcherIpc'; -import { ChokidarWatcherService } from 'vs/workbench/services/files/node/watcher/unix/chokidarWatcherService'; +import { WatcherChannel } from 'vs/platform/files/node/watcher/unix/watcherIpc'; +import { ChokidarWatcherService } from 'vs/platform/files/node/watcher/unix/chokidarWatcherService'; const server = new Server('watcher'); const service = new ChokidarWatcherService(); diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts b/src/vs/platform/files/node/watcher/unix/watcherIpc.ts similarity index 94% rename from src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts rename to src/vs/platform/files/node/watcher/unix/watcherIpc.ts index e59a0958b22..18bbeeaa64f 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts +++ b/src/vs/platform/files/node/watcher/unix/watcherIpc.ts @@ -6,7 +6,7 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IWatcherRequest, IWatcherService, IWatcherOptions } from './watcher'; import { Event } from 'vs/base/common/event'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; export class WatcherChannel implements IServerChannel { diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts b/src/vs/platform/files/node/watcher/unix/watcherService.ts similarity index 88% rename from src/vs/workbench/services/files/node/watcher/unix/watcherService.ts rename to src/vs/platform/files/node/watcher/unix/watcherService.ts index 202b505d53a..18d55aec1d8 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts +++ b/src/vs/platform/files/node/watcher/unix/watcherService.ts @@ -5,10 +5,10 @@ import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; -import { WatcherChannelClient } from 'vs/workbench/services/files/node/watcher/unix/watcherIpc'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; +import { WatcherChannelClient } from 'vs/platform/files/node/watcher/unix/watcherIpc'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IWatcherRequest, IWatcherOptions } from 'vs/workbench/services/files/node/watcher/unix/watcher'; +import { IWatcherRequest, IWatcherOptions } from 'vs/platform/files/node/watcher/unix/watcher'; import { getPathFromAmdModule } from 'vs/base/common/amd'; export class FileWatcher extends Disposable { @@ -40,7 +40,7 @@ export class FileWatcher extends Disposable { serverName: 'File Watcher (chokidar)', args: ['--type=watcherService'], env: { - AMD_ENTRYPOINT: 'vs/workbench/services/files/node/watcher/unix/watcherApp', + AMD_ENTRYPOINT: 'vs/platform/files/node/watcher/unix/watcherApp', PIPE_LOGGING: 'true', VERBOSE_LOGGING: 'true' // transmit console logs from server to client } diff --git a/src/vs/workbench/services/files/node/watcher/watcher.ts b/src/vs/platform/files/node/watcher/watcher.ts similarity index 100% rename from src/vs/workbench/services/files/node/watcher/watcher.ts rename to src/vs/platform/files/node/watcher/watcher.ts diff --git a/src/vs/workbench/services/files/node/watcher/win32/CodeHelper.exe b/src/vs/platform/files/node/watcher/win32/CodeHelper.exe similarity index 100% rename from src/vs/workbench/services/files/node/watcher/win32/CodeHelper.exe rename to src/vs/platform/files/node/watcher/win32/CodeHelper.exe diff --git a/src/vs/workbench/services/files/node/watcher/win32/CodeHelper.md b/src/vs/platform/files/node/watcher/win32/CodeHelper.md similarity index 100% rename from src/vs/workbench/services/files/node/watcher/win32/CodeHelper.md rename to src/vs/platform/files/node/watcher/win32/CodeHelper.md diff --git a/src/vs/workbench/services/files/node/watcher/win32/csharpWatcherService.ts b/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts similarity index 94% rename from src/vs/workbench/services/files/node/watcher/win32/csharpWatcherService.ts rename to src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts index effcbc9472d..94050df7ee7 100644 --- a/src/vs/workbench/services/files/node/watcher/win32/csharpWatcherService.ts +++ b/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts @@ -7,7 +7,7 @@ import * as cp from 'child_process'; import { FileChangeType } from 'vs/platform/files/common/files'; import * as decoder from 'vs/base/node/decoder'; import * as glob from 'vs/base/common/glob'; -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; import { getPathFromAmdModule } from 'vs/base/common/amd'; export class OutOfProcessWin32FolderWatcher { @@ -50,7 +50,7 @@ export class OutOfProcessWin32FolderWatcher { args.push('-verbose'); } - this.handle = cp.spawn(getPathFromAmdModule(require, 'vs/workbench/services/files/node/watcher/win32/CodeHelper.exe'), args); + this.handle = cp.spawn(getPathFromAmdModule(require, 'vs/platform/files/node/watcher/win32/CodeHelper.exe'), args); const stdoutLineDecoder = new decoder.LineDecoder(); diff --git a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts b/src/vs/platform/files/node/watcher/win32/watcherService.ts similarity index 91% rename from src/vs/workbench/services/files/node/watcher/win32/watcherService.ts rename to src/vs/platform/files/node/watcher/win32/watcherService.ts index bab9258c1b5..c8f0d8fdfb5 100644 --- a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts +++ b/src/vs/platform/files/node/watcher/win32/watcherService.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDiskFileChange, ILogMessage } from 'vs/workbench/services/files/node/watcher/watcher'; -import { OutOfProcessWin32FolderWatcher } from 'vs/workbench/services/files/node/watcher/win32/csharpWatcherService'; +import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; +import { OutOfProcessWin32FolderWatcher } from 'vs/platform/files/node/watcher/win32/csharpWatcherService'; import { posix } from 'vs/base/common/path'; import { rtrim, endsWith } from 'vs/base/common/strings'; import { IDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/services/files/test/browser/fileService.test.ts b/src/vs/platform/files/test/browser/fileService.test.ts similarity index 95% rename from src/vs/workbench/services/files/test/browser/fileService.test.ts rename to src/vs/platform/files/test/browser/fileService.test.ts index 01af38d61c9..2eb366a65f0 100644 --- a/src/vs/workbench/services/files/test/browser/fileService.test.ts +++ b/src/vs/platform/files/test/browser/fileService.test.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { URI } from 'vs/base/common/uri'; import { IFileSystemProviderRegistrationEvent, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { NullFileSystemProvider } from 'vs/workbench/test/workbenchTestServices'; import { NullLogService } from 'vs/platform/log/common/log'; import { timeout } from 'vs/base/common/async'; +import { NullFileSystemProvider } from 'vs/platform/files/test/common/nullFileSystemProvider'; suite('File Service', () => { diff --git a/src/vs/platform/files/test/common/nullFileSystemProvider.ts b/src/vs/platform/files/test/common/nullFileSystemProvider.ts new file mode 100644 index 00000000000..b4b1c3af6fe --- /dev/null +++ b/src/vs/platform/files/test/common/nullFileSystemProvider.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { FileSystemProviderCapabilities, IFileSystemProvider, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, IFileChange } from 'vs/platform/files/common/files'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { Event } from 'vs/base/common/event'; + +export class NullFileSystemProvider implements IFileSystemProvider { + + capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly; + + onDidChangeCapabilities: Event = Event.None; + onDidChangeFile: Event = Event.None; + + constructor(private disposableFactory: () => IDisposable = () => Disposable.None) { } + + watch(resource: URI, opts: IWatchOptions): IDisposable { return this.disposableFactory(); } + stat(resource: URI): Promise { return Promise.resolve(undefined!); } + mkdir(resource: URI): Promise { return Promise.resolve(undefined!); } + readdir(resource: URI): Promise<[string, FileType][]> { return Promise.resolve(undefined!); } + delete(resource: URI, opts: FileDeleteOptions): Promise { return Promise.resolve(undefined!); } + rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise { return Promise.resolve(undefined!); } + copy?(from: URI, to: URI, opts: FileOverwriteOptions): Promise { return Promise.resolve(undefined!); } + readFile?(resource: URI): Promise { return Promise.resolve(undefined!); } + writeFile?(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { return Promise.resolve(undefined!); } + open?(resource: URI, opts: FileOpenOptions): Promise { return Promise.resolve(undefined!); } + close?(fd: number): Promise { return Promise.resolve(undefined!); } + read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return Promise.resolve(undefined!); } + write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return Promise.resolve(undefined!); } +} \ No newline at end of file diff --git a/src/vs/workbench/services/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts similarity index 95% rename from src/vs/workbench/services/files/test/node/diskFileService.test.ts rename to src/vs/platform/files/test/node/diskFileService.test.ts index f5394917d84..6d10050ec0e 100644 --- a/src/vs/workbench/services/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -5,22 +5,22 @@ import * as assert from 'assert'; import { tmpdir } from 'os'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { generateUuid } from 'vs/base/common/uuid'; import { join, basename, dirname, posix } from 'vs/base/common/path'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { copy, rimraf, symlink, RimRafMode, rimrafSync } from 'vs/base/node/pfs'; import { URI } from 'vs/base/common/uri'; -import { existsSync, statSync, readdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, mkdirSync, createReadStream, ReadStream } from 'fs'; +import { existsSync, statSync, readdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, mkdirSync, createReadStream } from 'fs'; import { FileOperation, FileOperationEvent, IFileStat, FileOperationResult, FileSystemProviderCapabilities, FileChangeType, IFileChange, FileChangesEvent, FileOperationError, etag, IStat, IFileStatWithMetadata } from 'vs/platform/files/common/files'; import { NullLogService } from 'vs/platform/log/common/log'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; -import { VSBuffer, VSBufferReadable, writeableBufferStream, VSBufferReadableStream, bufferToReadable, bufferToStream } from 'vs/base/common/buffer'; +import { VSBuffer, VSBufferReadable, toVSBufferReadableStream, VSBufferReadableStream, bufferToReadable, bufferToStream } from 'vs/base/common/buffer'; function getByName(root: IFileStat, name: string): IFileStat | null { if (root.children === undefined) { @@ -58,16 +58,6 @@ function toLineByLineReadable(content: string): VSBufferReadable { }; } -function nodeStreamToVSBufferStream(stream: ReadStream): VSBufferReadableStream { - const vsbufferStream = writeableBufferStream(); - - stream.on('data', data => vsbufferStream.write(VSBuffer.wrap(data))); - stream.on('end', () => vsbufferStream.end()); - stream.on('error', error => vsbufferStream.error(error)); - - return vsbufferStream; -} - export class TestDiskFileSystemProvider extends DiskFileSystemProvider { totalBytesRead: number = 0; @@ -1573,7 +1563,7 @@ suite('Disk File Service', () => { const source = URI.file(join(testDir, 'small.txt')); const target = URI.file(join(testDir, 'small-copy.txt')); - const fileStat = await service.writeFile(target, nodeStreamToVSBufferStream(createReadStream(source.fsPath))); + const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); assert.equal(fileStat.name, 'small-copy.txt'); assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); @@ -1585,7 +1575,7 @@ suite('Disk File Service', () => { const source = URI.file(join(testDir, 'lorem.txt')); const target = URI.file(join(testDir, 'lorem-copy.txt')); - const fileStat = await service.writeFile(target, nodeStreamToVSBufferStream(createReadStream(source.fsPath))); + const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); assert.equal(fileStat.name, 'lorem-copy.txt'); assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); @@ -1597,7 +1587,7 @@ suite('Disk File Service', () => { const source = URI.file(join(testDir, 'small.txt')); const target = URI.file(join(testDir, 'small-copy.txt')); - const fileStat = await service.writeFile(target, nodeStreamToVSBufferStream(createReadStream(source.fsPath))); + const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); assert.equal(fileStat.name, 'small-copy.txt'); assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); @@ -1609,7 +1599,7 @@ suite('Disk File Service', () => { const source = URI.file(join(testDir, 'lorem.txt')); const target = URI.file(join(testDir, 'lorem-copy.txt')); - const fileStat = await service.writeFile(target, nodeStreamToVSBufferStream(createReadStream(source.fsPath))); + const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); assert.equal(fileStat.name, 'lorem-copy.txt'); assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); @@ -1706,7 +1696,9 @@ suite('Disk File Service', () => { assert.ok(!error); }); - test('watch - file', done => { + const runWatchTests = isLinux; + + (runWatchTests ? test : test.skip)('watch - file', done => { const toWatch = URI.file(join(testDir, 'index-watch1.html')); writeFileSync(toWatch.fsPath, 'Init'); @@ -1715,11 +1707,7 @@ suite('Disk File Service', () => { setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50); }); - test('watch - file symbolic link', async done => { - if (isWindows) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests && !isWindows /* symbolic links not reliable on windows */ ? test : test.skip)('watch - file symbolic link', async done => { const toWatch = URI.file(join(testDir, 'lorem.txt-linked')); await symlink(join(testDir, 'lorem.txt'), toWatch.fsPath); @@ -1728,11 +1716,7 @@ suite('Disk File Service', () => { setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50); }); - test('watch - file - multiple writes', done => { - if (isWindows) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - file - multiple writes', done => { const toWatch = URI.file(join(testDir, 'index-watch1.html')); writeFileSync(toWatch.fsPath, 'Init'); @@ -1743,7 +1727,7 @@ suite('Disk File Service', () => { setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes 3'), 20); }); - test('watch - file - delete file', done => { + (runWatchTests ? test : test.skip)('watch - file - delete file', done => { const toWatch = URI.file(join(testDir, 'index-watch1.html')); writeFileSync(toWatch.fsPath, 'Init'); @@ -1752,11 +1736,7 @@ suite('Disk File Service', () => { setTimeout(() => unlinkSync(toWatch.fsPath), 50); }); - test('watch - file - rename file', done => { - if (isWindows) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - file - rename file', done => { const toWatch = URI.file(join(testDir, 'index-watch1.html')); const toWatchRenamed = URI.file(join(testDir, 'index-watch1-renamed.html')); writeFileSync(toWatch.fsPath, 'Init'); @@ -1766,7 +1746,7 @@ suite('Disk File Service', () => { setTimeout(() => renameSync(toWatch.fsPath, toWatchRenamed.fsPath), 50); }); - test('watch - file - rename file (different case)', done => { + (runWatchTests ? test : test.skip)('watch - file - rename file (different case)', done => { const toWatch = URI.file(join(testDir, 'index-watch1.html')); const toWatchRenamed = URI.file(join(testDir, 'INDEX-watch1.html')); writeFileSync(toWatch.fsPath, 'Init'); @@ -1780,7 +1760,7 @@ suite('Disk File Service', () => { setTimeout(() => renameSync(toWatch.fsPath, toWatchRenamed.fsPath), 50); }); - test('watch - file (atomic save)', function (done) { + (runWatchTests ? test : test.skip)('watch - file (atomic save)', function (done) { const toWatch = URI.file(join(testDir, 'index-watch2.html')); writeFileSync(toWatch.fsPath, 'Init'); @@ -1796,11 +1776,7 @@ suite('Disk File Service', () => { }, 50); }); - test('watch - folder (non recursive) - change file', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - folder (non recursive) - change file', done => { const watchDir = URI.file(join(testDir, 'watch3')); mkdirSync(watchDir.fsPath); @@ -1812,11 +1788,7 @@ suite('Disk File Service', () => { setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50); }); - test('watch - folder (non recursive) - add file', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - folder (non recursive) - add file', done => { const watchDir = URI.file(join(testDir, 'watch4')); mkdirSync(watchDir.fsPath); @@ -1827,11 +1799,7 @@ suite('Disk File Service', () => { setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50); }); - test('watch - folder (non recursive) - delete file', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - folder (non recursive) - delete file', done => { const watchDir = URI.file(join(testDir, 'watch5')); mkdirSync(watchDir.fsPath); @@ -1843,11 +1811,7 @@ suite('Disk File Service', () => { setTimeout(() => unlinkSync(file.fsPath), 50); }); - test('watch - folder (non recursive) - add folder', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - folder (non recursive) - add folder', done => { const watchDir = URI.file(join(testDir, 'watch6')); mkdirSync(watchDir.fsPath); @@ -1858,11 +1822,7 @@ suite('Disk File Service', () => { setTimeout(() => mkdirSync(folder.fsPath), 50); }); - test('watch - folder (non recursive) - delete folder', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - folder (non recursive) - delete folder', done => { const watchDir = URI.file(join(testDir, 'watch7')); mkdirSync(watchDir.fsPath); @@ -1874,11 +1834,7 @@ suite('Disk File Service', () => { setTimeout(() => rimrafSync(folder.fsPath), 50); }); - test('watch - folder (non recursive) - symbolic link - change file', async done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests && !isWindows /* symbolic links not reliable on windows */ ? test : test.skip)('watch - folder (non recursive) - symbolic link - change file', async done => { const watchDir = URI.file(join(testDir, 'deep-link')); await symlink(join(testDir, 'deep'), watchDir.fsPath); @@ -1890,11 +1846,7 @@ suite('Disk File Service', () => { setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50); }); - test('watch - folder (non recursive) - rename file', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests ? test : test.skip)('watch - folder (non recursive) - rename file', done => { const watchDir = URI.file(join(testDir, 'watch8')); mkdirSync(watchDir.fsPath); @@ -1908,11 +1860,7 @@ suite('Disk File Service', () => { setTimeout(() => renameSync(file.fsPath, fileRenamed.fsPath), 50); }); - test('watch - folder (non recursive) - rename file (different case)', done => { - if (!isLinux) { - return done(); // watch tests are flaky on other platforms - } - + (runWatchTests && isLinux /* this test requires a case sensitive file system */ ? test : test.skip)('watch - folder (non recursive) - rename file (different case)', done => { const watchDir = URI.file(join(testDir, 'watch8')); mkdirSync(watchDir.fsPath); diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/examples/company.js b/src/vs/platform/files/test/node/fixtures/resolver/examples/company.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/examples/company.js rename to src/vs/platform/files/test/node/fixtures/resolver/examples/company.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/examples/conway.js b/src/vs/platform/files/test/node/fixtures/resolver/examples/conway.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/examples/conway.js rename to src/vs/platform/files/test/node/fixtures/resolver/examples/conway.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/examples/employee.js b/src/vs/platform/files/test/node/fixtures/resolver/examples/employee.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/examples/employee.js rename to src/vs/platform/files/test/node/fixtures/resolver/examples/employee.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/examples/small.js b/src/vs/platform/files/test/node/fixtures/resolver/examples/small.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/examples/small.js rename to src/vs/platform/files/test/node/fixtures/resolver/examples/small.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/index.html b/src/vs/platform/files/test/node/fixtures/resolver/index.html similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/index.html rename to src/vs/platform/files/test/node/fixtures/resolver/index.html diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/company.js b/src/vs/platform/files/test/node/fixtures/resolver/other/deep/company.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/company.js rename to src/vs/platform/files/test/node/fixtures/resolver/other/deep/company.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/conway.js b/src/vs/platform/files/test/node/fixtures/resolver/other/deep/conway.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/conway.js rename to src/vs/platform/files/test/node/fixtures/resolver/other/deep/conway.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/employee.js b/src/vs/platform/files/test/node/fixtures/resolver/other/deep/employee.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/employee.js rename to src/vs/platform/files/test/node/fixtures/resolver/other/deep/employee.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/small.js b/src/vs/platform/files/test/node/fixtures/resolver/other/deep/small.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/other/deep/small.js rename to src/vs/platform/files/test/node/fixtures/resolver/other/deep/small.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/resolver/site.css b/src/vs/platform/files/test/node/fixtures/resolver/site.css similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/resolver/site.css rename to src/vs/platform/files/test/node/fixtures/resolver/site.css diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/binary.txt b/src/vs/platform/files/test/node/fixtures/service/binary.txt similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/binary.txt rename to src/vs/platform/files/test/node/fixtures/service/binary.txt diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/deep/company.js b/src/vs/platform/files/test/node/fixtures/service/deep/company.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/deep/company.js rename to src/vs/platform/files/test/node/fixtures/service/deep/company.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/deep/conway.js b/src/vs/platform/files/test/node/fixtures/service/deep/conway.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/deep/conway.js rename to src/vs/platform/files/test/node/fixtures/service/deep/conway.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/deep/employee.js b/src/vs/platform/files/test/node/fixtures/service/deep/employee.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/deep/employee.js rename to src/vs/platform/files/test/node/fixtures/service/deep/employee.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/deep/small.js b/src/vs/platform/files/test/node/fixtures/service/deep/small.js similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/deep/small.js rename to src/vs/platform/files/test/node/fixtures/service/deep/small.js diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/index.html b/src/vs/platform/files/test/node/fixtures/service/index.html similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/index.html rename to src/vs/platform/files/test/node/fixtures/service/index.html diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/lorem.txt b/src/vs/platform/files/test/node/fixtures/service/lorem.txt similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/lorem.txt rename to src/vs/platform/files/test/node/fixtures/service/lorem.txt diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/small.txt b/src/vs/platform/files/test/node/fixtures/service/small.txt similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/small.txt rename to src/vs/platform/files/test/node/fixtures/service/small.txt diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/small_umlaut.txt b/src/vs/platform/files/test/node/fixtures/service/small_umlaut.txt similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/small_umlaut.txt rename to src/vs/platform/files/test/node/fixtures/service/small_umlaut.txt diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/some_utf16le.css b/src/vs/platform/files/test/node/fixtures/service/some_utf16le.css similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/some_utf16le.css rename to src/vs/platform/files/test/node/fixtures/service/some_utf16le.css diff --git a/src/vs/workbench/services/files/test/node/fixtures/service/some_utf8_bom.txt b/src/vs/platform/files/test/node/fixtures/service/some_utf8_bom.txt similarity index 100% rename from src/vs/workbench/services/files/test/node/fixtures/service/some_utf8_bom.txt rename to src/vs/platform/files/test/node/fixtures/service/some_utf8_bom.txt diff --git a/src/vs/workbench/services/files/test/node/normalizer.test.ts b/src/vs/platform/files/test/node/normalizer.test.ts similarity index 99% rename from src/vs/workbench/services/files/test/node/normalizer.test.ts rename to src/vs/platform/files/test/node/normalizer.test.ts index d08747713aa..3f14bb70246 100644 --- a/src/vs/workbench/services/files/test/node/normalizer.test.ts +++ b/src/vs/platform/files/test/node/normalizer.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import * as platform from 'vs/base/common/platform'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { URI as uri } from 'vs/base/common/uri'; -import { IDiskFileChange, normalizeFileChanges, toFileChanges } from 'vs/workbench/services/files/node/watcher/watcher'; +import { IDiskFileChange, normalizeFileChanges, toFileChanges } from 'vs/platform/files/node/watcher/watcher'; import { Event, Emitter } from 'vs/base/common/event'; function toFileChangesEvent(changes: IDiskFileChange[]): FileChangesEvent { diff --git a/src/vs/platform/history/common/historyStorage.ts b/src/vs/platform/history/common/historyStorage.ts index 2d5f47f3981..089d73ec313 100644 --- a/src/vs/platform/history/common/historyStorage.ts +++ b/src/vs/platform/history/common/historyStorage.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { UriComponents, URI } from 'vs/base/common/uri'; import { IRecentlyOpened, isRecentFolder } from 'vs/platform/history/common/history'; +import { ILogService } from 'vs/platform/log/common/log'; interface ISerializedRecentlyOpened { workspaces3: Array; // workspace or URI.toString() // added in 1.32 @@ -31,32 +32,41 @@ function isUriComponents(curr: any): curr is UriComponents { export type RecentlyOpenedStorageData = object; -export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefined): IRecentlyOpened { +export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefined, logService: ILogService): IRecentlyOpened { const result: IRecentlyOpened = { workspaces: [], files: [] }; if (data) { + const restoreGracefully = function (entries: T[], func: (entry: T, index: number) => void) { + for (let i = 0; i < entries.length; i++) { + try { + func(entries[i], i); + } catch (e) { + logService.warn(`Error restoring recent entry ${JSON.stringify(entries[i])}: ${e.toString()}. Skip entry.`); + } + } + }; + const storedRecents = data as ISerializedRecentlyOpened & ILegacySerializedRecentlyOpened; if (Array.isArray(storedRecents.workspaces3)) { - for (let i = 0; i < storedRecents.workspaces3.length; i++) { - const workspace = storedRecents.workspaces3[i]; + restoreGracefully(storedRecents.workspaces3, (workspace, i) => { const label: string | undefined = (Array.isArray(storedRecents.workspaceLabels) && storedRecents.workspaceLabels[i]) || undefined; if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configURIPath === 'string') { result.workspaces.push({ label, workspace: { id: workspace.id, configPath: URI.parse(workspace.configURIPath) } }); } else if (typeof workspace === 'string') { result.workspaces.push({ label, folderUri: URI.parse(workspace) }); } - } + }); } else if (Array.isArray(storedRecents.workspaces2)) { - for (const workspace of storedRecents.workspaces2) { + restoreGracefully(storedRecents.workspaces2, workspace => { if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configPath === 'string') { result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } }); } else if (typeof workspace === 'string') { result.workspaces.push({ folderUri: URI.parse(workspace) }); } - } + }); } else if (Array.isArray(storedRecents.workspaces)) { // TODO@martin legacy support can be removed at some point (6 month?) // format of 1.25 and before - for (const workspace of storedRecents.workspaces) { + restoreGracefully(storedRecents.workspaces, workspace => { if (typeof workspace === 'string') { result.workspaces.push({ folderUri: URI.file(workspace) }); } else if (isLegacySerializedWorkspace(workspace)) { @@ -65,23 +75,21 @@ export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefine // added by 1.26-insiders result.workspaces.push({ folderUri: URI.revive(workspace) }); } - } + }); } - if (Array.isArray(storedRecents.files2)) { - for (let i = 0; i < storedRecents.files2.length; i++) { - const file = storedRecents.files2[i]; + restoreGracefully(storedRecents.files2, (file, i) => { const label: string | undefined = (Array.isArray(storedRecents.fileLabels) && storedRecents.fileLabels[i]) || undefined; if (typeof file === 'string') { result.files.push({ label, fileUri: URI.parse(file) }); } - } + }); } else if (Array.isArray(storedRecents.files)) { - for (const file of storedRecents.files) { + restoreGracefully(storedRecents.files, file => { if (typeof file === 'string') { result.files.push({ fileUri: URI.file(file) }); } - } + }); } } diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index c55fcc6e8cc..6447b2c65e1 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -270,7 +270,7 @@ export class HistoryMainService implements IHistoryMainService { private getRecentlyOpenedFromStorage(): IRecentlyOpened { const storedRecents = this.stateService.getItem(HistoryMainService.recentlyOpenedStorageKey); - return restoreRecentlyOpened(storedRecents); + return restoreRecentlyOpened(storedRecents, this.logService); } private saveRecentlyOpened(recent: IRecentlyOpened): void { diff --git a/src/vs/platform/history/test/electron-main/historyStorage.test.ts b/src/vs/platform/history/test/electron-main/historyStorage.test.ts index cb591285b1a..4a76b1515ea 100644 --- a/src/vs/platform/history/test/electron-main/historyStorage.test.ts +++ b/src/vs/platform/history/test/electron-main/historyStorage.test.ts @@ -10,6 +10,7 @@ import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; import { IRecentlyOpened, isRecentFolder, IRecentFolder, IRecentWorkspace } from 'vs/platform/history/common/history'; import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; +import { NullLogService } from 'vs/platform/log/common/log'; function toWorkspace(uri: URI): IWorkspaceIdentifier { return { @@ -51,7 +52,7 @@ function assertEqualRecentlyOpened(actual: IRecentlyOpened, expected: IRecentlyO function assertRestoring(state: IRecentlyOpened, message?: string) { const stored = toStoreData(state); - const restored = restoreRecentlyOpened(stored); + const restored = restoreRecentlyOpened(stored, new NullLogService()); assertEqualRecentlyOpened(state, restored, message); } @@ -118,7 +119,7 @@ suite('History Storage', () => { ] }`; - let actual = restoreRecentlyOpened(JSON.parse(v1_25_win)); + let actual = restoreRecentlyOpened(JSON.parse(v1_25_win), new NullLogService()); let expected: IRecentlyOpened = { files: [{ fileUri: URI.file('C:\\workspaces\\test.code-workspace') }, { fileUri: URI.file('C:\\workspaces\\testing\\test-ext\\.gitignore') }], workspaces: [ @@ -146,7 +147,7 @@ suite('History Storage', () => { ] }`; - let actual = restoreRecentlyOpened(JSON.parse(v1_31_win)); + let actual = restoreRecentlyOpened(JSON.parse(v1_31_win), new NullLogService()); let expected: IRecentlyOpened = { files: [{ fileUri: URI.parse('file:///c%3A/workspaces/vscode/.yarnrc') }], workspaces: [ @@ -173,7 +174,7 @@ suite('History Storage', () => { ] }`; - let windowsState = restoreRecentlyOpened(JSON.parse(v1_32)); + let windowsState = restoreRecentlyOpened(JSON.parse(v1_32), new NullLogService()); let expected: IRecentlyOpened = { files: [{ fileUri: URI.parse('file:///home/user/.config/code-oss-dev/storage.json') }], workspaces: [ @@ -206,7 +207,7 @@ suite('History Storage', () => { ] }`; - let windowsState = restoreRecentlyOpened(JSON.parse(v1_33)); + let windowsState = restoreRecentlyOpened(JSON.parse(v1_33), new NullLogService()); let expected: IRecentlyOpened = { files: [{ label: 'def', fileUri: URI.parse('file:///home/user/.config/code-oss-dev/storage.json') }], workspaces: [ diff --git a/src/vs/platform/instantiation/common/extensions.ts b/src/vs/platform/instantiation/common/extensions.ts index 5ecd792c518..5957b7924f5 100644 --- a/src/vs/platform/instantiation/common/extensions.ts +++ b/src/vs/platform/instantiation/common/extensions.ts @@ -6,18 +6,12 @@ import { SyncDescriptor } from './descriptors'; import { ServiceIdentifier, IConstructorSignature0 } from './instantiation'; - -export interface IServiceContribution { - id: ServiceIdentifier; - descriptor: SyncDescriptor; -} - -const _registry: IServiceContribution[] = []; +const _registry: [ServiceIdentifier, SyncDescriptor][] = []; export function registerSingleton(id: ServiceIdentifier, ctor: IConstructorSignature0, supportsDelayedInstantiation?: boolean): void { - _registry.push({ id, descriptor: new SyncDescriptor(ctor, [], supportsDelayedInstantiation) }); + _registry.push([id, new SyncDescriptor(ctor, [], supportsDelayedInstantiation)]); } -export function getServices(): IServiceContribution[] { +export function getSingletonServiceDescriptors(): [ServiceIdentifier, SyncDescriptor][] { return _registry; } diff --git a/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts index 918cd9bb808..06ff2870345 100644 --- a/src/vs/platform/instantiation/common/instantiation.ts +++ b/src/vs/platform/instantiation/common/instantiation.ts @@ -59,7 +59,8 @@ export interface IConstructorSignature8 { } export interface ServicesAccessor { - get(id: ServiceIdentifier, isOptional?: typeof optional): T; + get(id: ServiceIdentifier): T; + get(id: ServiceIdentifier, isOptional: typeof optional): T | undefined; } export const IInstantiationService = createDecorator('instantiationService'); diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index 1436cfa6604..29d559eab4d 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext, ContextKeyOrExpr } from 'vs/platform/contextkey/common/contextkey'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { keys } from 'vs/base/common/map'; @@ -171,7 +171,6 @@ export class KeybindingResolver { /** * Returns true if it is provable `a` implies `b`. - * **Precondition**: Assumes `a` and `b` are normalized! */ public static whenIsEntirelyIncluded(a: ContextKeyExpr | null | undefined, b: ContextKeyExpr | null | undefined): boolean { if (!b) { @@ -181,26 +180,35 @@ export class KeybindingResolver { return false; } - const aExpressions: ContextKeyExpr[] = ((a instanceof ContextKeyAndExpr) ? a.expr : [a]); - const bExpressions: ContextKeyExpr[] = ((b instanceof ContextKeyAndExpr) ? b.expr : [b]); + return this._implies(a, b); + } - let aIndex = 0; - for (const bExpr of bExpressions) { - let bExprMatched = false; - while (!bExprMatched && aIndex < aExpressions.length) { - let aExpr = aExpressions[aIndex]; - if (aExpr.equals(bExpr)) { - bExprMatched = true; - } - aIndex++; + /** + * Returns true if it is provable `p` implies `q`. + */ + private static _implies(p: ContextKeyExpr, q: ContextKeyExpr): boolean { + const notP = p.negate(); + + const terminals = (node: ContextKeyExpr) => { + if (node instanceof ContextKeyOrExpr) { + return node.expr; } + return [node]; + }; - if (!bExprMatched) { - return false; + let expr = terminals(notP).concat(terminals(q)); + for (let i = 0; i < expr.length; i++) { + const a = expr[i]; + const notA = a.negate(); + for (let j = i + 1; j < expr.length; j++) { + const b = expr[j]; + if (notA.equals(b)) { + return true; + } } } - return true; + return false; } public getDefaultBoundCommands(): Map { diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index 4798e84518d..ec4a46372a6 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -121,6 +121,7 @@ suite('AbstractKeybindingService', () => { let commandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand: (commandId: string, ...args: any[]): Promise => { executeCommandCalls.push({ commandId: commandId, diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index a4488cffb17..c85003be1ac 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; import { OS } from 'vs/base/common/platform'; -import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; @@ -20,13 +20,13 @@ function createContext(ctx: any) { suite('KeybindingResolver', () => { - function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): ResolvedKeybindingItem { + function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean): ResolvedKeybindingItem { const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); return new ResolvedKeybindingItem( resolvedKeybinding, command, commandArgs, - when ? when.normalize() : undefined, + when, isDefault ); } @@ -191,64 +191,41 @@ suite('KeybindingResolver', () => { }); test('contextIsEntirelyIncluded', () => { - let assertIsIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => { - let tmpA = new ContextKeyAndExpr(a).normalize(); - let tmpB = new ContextKeyAndExpr(b).normalize(); - assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), true); + const assertIsIncluded = (a: string | null, b: string | null) => { + assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), true); }; - let assertIsNotIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => { - let tmpA = new ContextKeyAndExpr(a).normalize(); - let tmpB = new ContextKeyAndExpr(b).normalize(); - assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), false); + const assertIsNotIncluded = (a: string | null, b: string | null) => { + assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), false); }; - let key1IsTrue = ContextKeyExpr.equals('key1', true); - let key1IsNotFalse = ContextKeyExpr.notEquals('key1', false); - let key1IsFalse = ContextKeyExpr.equals('key1', false); - let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true); - let key2IsTrue = ContextKeyExpr.equals('key2', true); - let key2IsNotFalse = ContextKeyExpr.notEquals('key2', false); - let key3IsTrue = ContextKeyExpr.equals('key3', true); - let key4IsTrue = ContextKeyExpr.equals('key4', true); - assertIsIncluded([key1IsTrue], null!); - assertIsIncluded([key1IsTrue], []); - assertIsIncluded([key1IsTrue], [key1IsTrue]); - assertIsIncluded([key1IsTrue], [key1IsNotFalse]); + assertIsIncluded('key1', null); + assertIsIncluded('key1', ''); + assertIsIncluded('key1', 'key1'); + assertIsIncluded('!key1', ''); + assertIsIncluded('!key1', '!key1'); + assertIsIncluded('key2', ''); + assertIsIncluded('key2', 'key2'); + assertIsIncluded('key1 && key1 && key2 && key2', 'key2'); + assertIsIncluded('key1 && key2', 'key2'); + assertIsIncluded('key1 && key2', 'key1'); + assertIsIncluded('key1 && key2', ''); + assertIsIncluded('key1', 'key1 || key2'); + assertIsIncluded('key1 || !key1', 'key2 || !key2'); + assertIsIncluded('key1', 'key1 || key2 && key3'); - assertIsIncluded([key1IsFalse], []); - assertIsIncluded([key1IsFalse], [key1IsFalse]); - assertIsIncluded([key1IsFalse], [key1IsNotTrue]); - - assertIsIncluded([key2IsNotFalse], []); - assertIsIncluded([key2IsNotFalse], [key2IsNotFalse]); - assertIsIncluded([key2IsNotFalse], [key2IsTrue]); - - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsTrue]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsNotFalse]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsTrue]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsNotFalse]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], []); - - assertIsNotIncluded([key1IsTrue], [key1IsFalse]); - assertIsNotIncluded([key1IsTrue], [key1IsNotTrue]); - assertIsNotIncluded([key1IsNotFalse], [key1IsFalse]); - assertIsNotIncluded([key1IsNotFalse], [key1IsNotTrue]); - - assertIsNotIncluded([key1IsFalse], [key1IsTrue]); - assertIsNotIncluded([key1IsFalse], [key1IsNotFalse]); - assertIsNotIncluded([key1IsNotTrue], [key1IsTrue]); - assertIsNotIncluded([key1IsNotTrue], [key1IsNotFalse]); - - assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key3IsTrue]); - assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key4IsTrue]); - assertIsNotIncluded([key1IsTrue], [key2IsTrue]); - assertIsNotIncluded([], [key2IsTrue]); - assertIsNotIncluded(null!, [key2IsTrue]); + assertIsNotIncluded('key1', '!key1'); + assertIsNotIncluded('!key1', 'key1'); + assertIsNotIncluded('key1 && key2', 'key3'); + assertIsNotIncluded('key1 && key2', 'key4'); + assertIsNotIncluded('key1', 'key2'); + assertIsNotIncluded('key1 || key2', 'key2'); + assertIsNotIncluded('', 'key2'); + assertIsNotIncluded(null, 'key2'); }); test('resolve command', function () { - function _kbItem(keybinding: number, command: string, when: ContextKeyExpr): ResolvedKeybindingItem { + function _kbItem(keybinding: number, command: string, when: ContextKeyExpr | undefined): ResolvedKeybindingItem { return kbItem(keybinding, command, null, when, true); } diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index c192151f915..626a376d04b 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/lifecycle/common/lifecycleService.ts b/src/vs/platform/lifecycle/common/lifecycleService.ts index b325cde418a..2225c04ca99 100644 --- a/src/vs/platform/lifecycle/common/lifecycleService.ts +++ b/src/vs/platform/lifecycle/common/lifecycleService.ts @@ -16,13 +16,13 @@ export abstract class AbstractLifecycleService extends Disposable implements ILi _serviceBrand: ServiceIdentifier; protected readonly _onBeforeShutdown = this._register(new Emitter()); - get onBeforeShutdown(): Event { return this._onBeforeShutdown.event; } + readonly onBeforeShutdown: Event = this._onBeforeShutdown.event; protected readonly _onWillShutdown = this._register(new Emitter()); - get onWillShutdown(): Event { return this._onWillShutdown.event; } + readonly onWillShutdown: Event = this._onWillShutdown.event; protected readonly _onShutdown = this._register(new Emitter()); - get onShutdown(): Event { return this._onShutdown.event; } + readonly onShutdown: Event = this._onShutdown.event; protected _startupKind: StartupKind; get startupKind(): StartupKind { return this._startupKind; } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 6261e15b41d..0ef822bae84 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -247,7 +247,7 @@ export class WorkbenchList extends List { constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: IListRenderer[], + renderers: IListRenderer[], options: IListOptions, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @@ -787,7 +787,7 @@ export class WorkbenchObjectTree, TFilterData = void> constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], options: IObjectTreeOptions, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @@ -813,7 +813,7 @@ export class WorkbenchDataTree extends DataTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], dataSource: IDataSource, options: IDataTreeOptions, @IContextKeyService contextKeyService: IContextKeyService, @@ -840,7 +840,7 @@ export class WorkbenchAsyncDataTree extends Async constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], dataSource: IAsyncDataSource, options: IAsyncDataTreeOptions, @IContextKeyService contextKeyService: IContextKeyService, diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 9461b506c21..235c4b12f36 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -39,6 +39,7 @@ export interface IRelatedInformation { export const enum MarkerTag { Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index c8091409e3f..76185f93da8 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -478,7 +478,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/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index 75549c25f55..173b575822e 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -254,7 +254,7 @@ export class NoOpNotification implements INotificationHandle { readonly progress = new NoOpProgress(); private readonly _onDidClose: Emitter = new Emitter(); - get onDidClose(): Event { return this._onDidClose.event; } + readonly onDidClose: Event = this._onDidClose.event; updateSeverity(severity: Severity): void { } updateMessage(message: NotificationMessage): void { } diff --git a/src/vs/platform/product/browser/productService.ts b/src/vs/platform/product/browser/productService.ts index 972e6aad642..fbdf03fd3e4 100644 --- a/src/vs/platform/product/browser/productService.ts +++ b/src/vs/platform/product/browser/productService.ts @@ -19,7 +19,7 @@ export class ProductService implements IProductService { get version(): string { return '1.35.0'; } - get commit(): string | undefined { return undefined; } + get commit(): string | undefined { return this.productConfiguration ? this.productConfiguration.commit : undefined; } get nameLong(): string { return ''; } @@ -34,4 +34,16 @@ export class ProductService implements IProductService { get sendASmile(): { reportIssueUrl: string, requestFeatureUrl: string } | undefined { return this.productConfiguration ? this.productConfiguration.sendASmile : undefined; } get extensionsGallery() { return this.productConfiguration ? this.productConfiguration.extensionsGallery : undefined; } + + get settingsSearchBuildId(): number | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchBuildId : undefined; } + + get settingsSearchUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchUrl : undefined; } + + get experimentsUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.experimentsUrl : undefined; } + + 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 90952c63254..d39dd65c08f 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -30,6 +30,17 @@ export interface IProductService { readonly reportIssueUrl: string; readonly requestFeatureUrl: string; }; + + readonly settingsSearchBuildId?: number; + readonly settingsSearchUrl?: string; + + readonly experimentsUrl?: string; + readonly extensionKeywords?: { [extension: string]: readonly string[]; }; + readonly extensionAllowedBadgeProviders?: readonly string[]; + + readonly aiConfig?: { + readonly asimovKey: string; + }; } export interface IProductConfiguration { @@ -61,8 +72,8 @@ export interface IProductConfiguration { readonly recommendationsUrl: string; }; extensionTips: { [id: string]: string; }; - extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; - readonly exeBasedExtensionTips: { [id: string]: { friendlyName: string, windowsPath?: string, recommendations: readonly string[] }; }; + extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; }; + readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; }; readonly extensionKeywords: { [extension: string]: readonly string[]; }; readonly extensionAllowedBadgeProviders: readonly string[]; readonly extensionAllowedProposedApi: readonly string[]; @@ -109,6 +120,14 @@ export interface IProductConfiguration { readonly uiExtensions?: readonly string[]; } +export interface IExeBasedExtensionTip { + friendlyName: string; + windowsPath?: string; + recommendations: readonly string[]; + important?: boolean; + exeFriendlyName?: string; +} + export interface ISurveyData { surveyId: string; surveyUrl: string; diff --git a/src/vs/platform/product/node/productService.ts b/src/vs/platform/product/node/productService.ts index 925b15e1d9a..4b98ff65d0f 100644 --- a/src/vs/platform/product/node/productService.ts +++ b/src/vs/platform/product/node/productService.ts @@ -29,4 +29,14 @@ export class ProductService implements IProductService { get sendASmile(): { reportIssueUrl: string, requestFeatureUrl: string } { return product.sendASmile; } get extensionsGallery() { return product.extensionsGallery; } + + get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; } + + get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; } + + get experimentsUrl(): string | undefined { return product.experimentsUrl; } + + get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return product.extensionKeywords; } + + get extensionAllowedBadgeProviders(): readonly string[] | undefined { return product.extensionAllowedBadgeProviders; } } \ No newline at end of file diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts new file mode 100644 index 00000000000..6b24ec07810 --- /dev/null +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -0,0 +1,146 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; +import { ISocket } from 'vs/base/parts/ipc/common/ipc.net'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { Event, Emitter } from 'vs/base/common/event'; + +export interface IWebSocketFactory { + create(url: string): IWebSocket; +} + +export interface IWebSocket { + readonly onData: Event; + readonly onOpen: Event; + readonly onClose: Event; + readonly onError: Event; + + send(data: ArrayBuffer | ArrayBufferView): void; + close(): void; +} + +class BrowserWebSocket implements IWebSocket { + + private readonly _onData = new Emitter(); + public readonly onData = this._onData.event; + + public readonly onOpen: Event; + public readonly onClose: Event; + public readonly onError: Event; + + private readonly _socket: WebSocket; + private readonly _fileReader: FileReader; + private readonly _queue: Blob[]; + private _isReading: boolean; + + private readonly _socketMessageListener: (ev: MessageEvent) => void; + + constructor(socket: WebSocket) { + this._socket = socket; + this._fileReader = new FileReader(); + this._queue = []; + this._isReading = false; + + this._fileReader.onload = (event) => { + this._isReading = false; + const buff = (event.target).result; + + this._onData.fire(buff); + + if (this._queue.length > 0) { + enqueue(this._queue.shift()!); + } + }; + + const enqueue = (blob: Blob) => { + if (this._isReading) { + this._queue.push(blob); + return; + } + this._isReading = true; + this._fileReader.readAsArrayBuffer(blob); + }; + + this._socketMessageListener = (ev: MessageEvent) => { + enqueue(ev.data); + }; + this._socket.addEventListener('message', this._socketMessageListener); + + this.onOpen = Event.fromDOMEventEmitter(this._socket, 'open'); + this.onClose = Event.fromDOMEventEmitter(this._socket, 'close'); + this.onError = Event.fromDOMEventEmitter(this._socket, 'error'); + } + + send(data: ArrayBuffer | ArrayBufferView): void { + this._socket.send(data); + } + + close(): void { + this._socket.close(); + this._socket.removeEventListener('message', this._socketMessageListener); + } +} + +export const defaultWebSocketFactory = new class implements IWebSocketFactory { + create(url: string): IWebSocket { + return new BrowserWebSocket(new WebSocket(url)); + } +}; + +class BrowserSocket implements ISocket { + public readonly socket: IWebSocket; + + constructor(socket: IWebSocket) { + this.socket = socket; + } + + public dispose(): void { + this.socket.close(); + } + + public onData(listener: (e: VSBuffer) => void): IDisposable { + return this.socket.onData((data) => listener(VSBuffer.wrap(new Uint8Array(data)))); + } + + public onClose(listener: () => void): IDisposable { + return this.socket.onClose(listener); + } + + public onEnd(listener: () => void): IDisposable { + return Disposable.None; + } + + public write(buffer: VSBuffer): void { + this.socket.send(buffer.buffer); + } + + public end(): void { + this.socket.close(); + } + +} + + +export class BrowserSocketFactory implements ISocketFactory { + private readonly _webSocketFactory: IWebSocketFactory; + + constructor(webSocketFactory: IWebSocketFactory | null | undefined) { + this._webSocketFactory = webSocketFactory || defaultWebSocketFactory; + } + + connect(host: string, port: number, query: string, callback: IConnectCallback): void { + const socket = this._webSocketFactory.create(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`); + const errorListener = socket.onError((err) => callback(err, undefined)); + socket.onOpen(() => { + errorListener.dispose(); + callback(undefined, new BrowserSocket(socket)); + }); + } +} + + + diff --git a/src/vs/platform/remote/browser/browserWebSocketFactory.ts b/src/vs/platform/remote/browser/browserWebSocketFactory.ts deleted file mode 100644 index 6d9ecbcf5a6..00000000000 --- a/src/vs/platform/remote/browser/browserWebSocketFactory.ts +++ /dev/null @@ -1,89 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; -import { ISocket } from 'vs/base/parts/ipc/common/ipc.net'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { onUnexpectedError } from 'vs/base/common/errors'; - -class BrowserSocket implements ISocket { - public readonly socket: WebSocket; - - constructor(socket: WebSocket) { - this.socket = socket; - } - - public dispose(): void { - this.socket.close(); - } - - public onData(_listener: (e: VSBuffer) => void): IDisposable { - const fileReader = new FileReader(); - const queue: Blob[] = []; - let isReading = false; - fileReader.onload = function (event) { - isReading = false; - const buff = (event.target).result; - - try { - _listener(VSBuffer.wrap(new Uint8Array(buff))); - } catch (err) { - onUnexpectedError(err); - } - - if (queue.length > 0) { - enqueue(queue.shift()!); - } - }; - const enqueue = (blob: Blob) => { - if (isReading) { - queue.push(blob); - return; - } - isReading = true; - fileReader.readAsArrayBuffer(blob); - }; - const listener = (e: MessageEvent) => { - enqueue(e.data); - }; - this.socket.addEventListener('message', listener); - return { - dispose: () => this.socket.removeEventListener('message', listener) - }; - } - - public onClose(listener: () => void): IDisposable { - this.socket.addEventListener('close', listener); - return { - dispose: () => this.socket.removeEventListener('close', listener) - }; - } - - public onEnd(listener: () => void): IDisposable { - return Disposable.None; - } - - public write(buffer: VSBuffer): void { - this.socket.send(buffer.buffer); - } - - public end(): void { - this.socket.close(); - } - -} - -export const browserWebSocketFactory = new class implements IWebSocketFactory { - connect(host: string, port: number, query: string, callback: IConnectCallback): void { - const errorListener = (err: any) => callback(err, undefined); - const socket = new WebSocket(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`); - socket.onopen = function (event) { - socket.removeEventListener('error', errorListener); - callback(undefined, new BrowserSocket(socket)); - }; - socket.addEventListener('error', errorListener); - } -}; diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index 37d42a5c391..5db4ac5683e 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { @@ -12,12 +12,16 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS constructor() { } - resolveAuthority(authority: string): Promise { + resolveAuthority(authority: string): Promise { if (authority.indexOf(':') >= 0) { const pieces = authority.split(':'); - return Promise.resolve({ authority, host: pieces[0], port: parseInt(pieces[1], 10) }); + return Promise.resolve({ + authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10) } + }); } - return Promise.resolve({ authority, host: authority, port: 80 }); + return Promise.resolve({ + authority: { authority, host: authority, port: 80 } + }); } clearResolvedAuthority(authority: string): void { diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts index 7c64d37917b..ad95b6751a7 100644 --- a/src/vs/platform/remote/common/remoteAgentConnection.ts +++ b/src/vs/platform/remote/common/remoteAgentConnection.ts @@ -57,7 +57,7 @@ interface ISimpleConnectionOptions { port: number; reconnectionToken: string; reconnectionProtocol: PersistentProtocol | null; - webSocketFactory: IWebSocketFactory; + socketFactory: ISocketFactory; signService: ISignService; } @@ -65,13 +65,13 @@ export interface IConnectCallback { (err: any | undefined, socket: ISocket | undefined): void; } -export interface IWebSocketFactory { +export interface ISocketFactory { connect(host: string, port: number, query: string, callback: IConnectCallback): void; } async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise { const protocol = await new Promise((c, e) => { - options.webSocketFactory.connect( + options.socketFactory.connect( options.host, options.port, `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, @@ -163,6 +163,7 @@ export interface IRemoteExtensionHostStartParams { debugId?: string; break?: boolean; port?: number | null; + env?: { [key: string]: string | null }; } interface IExtensionHostConnectionResult { @@ -201,7 +202,7 @@ async function doConnectRemoteAgentTunnel(options: ISimpleConnectionOptions, sta export interface IConnectionOptions { isBuilt: boolean; commit: string | undefined; - webSocketFactory: IWebSocketFactory; + socketFactory: ISocketFactory; addressProvider: IAddressProvider; signService: ISignService; } @@ -215,7 +216,7 @@ async function resolveConnectionOptions(options: IConnectionOptions, reconnectio port: port, reconnectionToken: reconnectionToken, reconnectionProtocol: reconnectionProtocol, - webSocketFactory: options.webSocketFactory, + socketFactory: options.socketFactory, signService: options.signService }; } @@ -255,7 +256,7 @@ function sleep(seconds: number): Promise { }); } -export const enum PersistenConnectionEventType { +export const enum PersistentConnectionEventType { ConnectionLost, ReconnectionWait, ReconnectionRunning, @@ -263,22 +264,22 @@ export const enum PersistenConnectionEventType { ConnectionGain } export class ConnectionLostEvent { - public readonly type = PersistenConnectionEventType.ConnectionLost; + public readonly type = PersistentConnectionEventType.ConnectionLost; } export class ReconnectionWaitEvent { - public readonly type = PersistenConnectionEventType.ReconnectionWait; + public readonly type = PersistentConnectionEventType.ReconnectionWait; constructor( public readonly durationSeconds: number ) { } } export class ReconnectionRunningEvent { - public readonly type = PersistenConnectionEventType.ReconnectionRunning; + public readonly type = PersistentConnectionEventType.ReconnectionRunning; } export class ConnectionGainEvent { - public readonly type = PersistenConnectionEventType.ConnectionGain; + public readonly type = PersistentConnectionEventType.ConnectionGain; } export class ReconnectionPermanentFailureEvent { - public readonly type = PersistenConnectionEventType.ReconnectionPermanentFailure; + public readonly type = PersistentConnectionEventType.ReconnectionPermanentFailure; } export type PersistenConnectionEvent = ConnectionGainEvent | ConnectionLostEvent | ReconnectionWaitEvent | ReconnectionRunningEvent | ReconnectionPermanentFailureEvent; diff --git a/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts index edc89fb407e..cefb3518ba0 100644 --- a/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts +++ b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts @@ -28,7 +28,7 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF readonly onDidChangeFile: Event = this._onDidChange.event; private _onDidWatchErrorOccur: Emitter = this._register(new Emitter()); - get onDidErrorOccur(): Event { return this._onDidWatchErrorOccur.event; } + readonly onDidErrorOccur: Event = this._onDidWatchErrorOccur.event; private readonly _onDidChangeCapabilities = this._register(new Emitter()); readonly onDidChangeCapabilities: Event = this._onDidChangeCapabilities.event; diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index fac355a4917..e9ba56563b3 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -13,6 +13,15 @@ export interface ResolvedAuthority { readonly port: number; } +export interface ResolvedOptions { + readonly extensionHostEnv?: { [key: string]: string | null }; +} + +export interface ResolverResult { + authority: ResolvedAuthority; + options?: ResolvedOptions; +} + export enum RemoteAuthorityResolverErrorCode { Unknown = 'Unknown', NotAvailable = 'NotAvailable', @@ -61,9 +70,9 @@ export interface IRemoteAuthorityResolverService { _serviceBrand: any; - resolveAuthority(authority: string): Promise; + resolveAuthority(authority: string): Promise; clearResolvedAuthority(authority: string): void; - setResolvedAuthority(resolvedAuthority: ResolvedAuthority): void; + setResolvedAuthority(resolvedAuthority: ResolvedAuthority, resolvedOptions?: ResolvedOptions): void; setResolvedAuthorityError(authority: string, err: any): void; } diff --git a/src/vs/platform/remote/common/remoteHosts.ts b/src/vs/platform/remote/common/remoteHosts.ts index 8ca915e74dc..5578246cc82 100644 --- a/src/vs/platform/remote/common/remoteHosts.ts +++ b/src/vs/platform/remote/common/remoteHosts.ts @@ -10,4 +10,16 @@ export const REMOTE_HOST_SCHEME = Schemas.vscodeRemote; export function getRemoteAuthority(uri: URI): string | undefined { return uri.scheme === REMOTE_HOST_SCHEME ? uri.authority : undefined; +} + +export function getRemoteName(authority: string | undefined): string | undefined { + if (!authority) { + return undefined; + } + const pos = authority.indexOf('+'); + if (pos < 0) { + // funky? bad authority? + return authority; + } + return authority.substr(0, pos); } \ No newline at end of file diff --git a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts index 0a97af69780..3cd1da3e018 100644 --- a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts @@ -3,15 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ipcRenderer as ipc } from 'electron'; import * as errors from 'vs/base/common/errors'; class PendingResolveAuthorityRequest { constructor( - public readonly resolve: (value: ResolvedAuthority) => void, + public readonly resolve: (value: ResolverResult) => void, public readonly reject: (err: any) => void, - public readonly promise: Promise, + public readonly promise: Promise, ) { } } @@ -26,11 +26,11 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS this._resolveAuthorityRequests = Object.create(null); } - resolveAuthority(authority: string): Promise { + resolveAuthority(authority: string): Promise { if (!this._resolveAuthorityRequests[authority]) { - let resolve: (value: ResolvedAuthority) => void; + let resolve: (value: ResolverResult) => void; let reject: (err: any) => void; - let promise = new Promise((_resolve, _reject) => { + let promise = new Promise((_resolve, _reject) => { resolve = _resolve; reject = _reject; }); @@ -46,11 +46,11 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS } } - setResolvedAuthority(resolvedAuthority: ResolvedAuthority) { + setResolvedAuthority(resolvedAuthority: ResolvedAuthority, options?: ResolvedOptions) { if (this._resolveAuthorityRequests[resolvedAuthority.authority]) { let request = this._resolveAuthorityRequests[resolvedAuthority.authority]; ipc.send('vscode:remoteAuthorityResolved', resolvedAuthority); - request.resolve(resolvedAuthority); + request.resolve({ authority: resolvedAuthority, options }); } } diff --git a/src/vs/platform/remote/node/nodeWebSocketFactory.ts b/src/vs/platform/remote/node/nodeSocketFactory.ts similarity index 89% rename from src/vs/platform/remote/node/nodeWebSocketFactory.ts rename to src/vs/platform/remote/node/nodeSocketFactory.ts index 9139f3e9992..44d68996140 100644 --- a/src/vs/platform/remote/node/nodeWebSocketFactory.ts +++ b/src/vs/platform/remote/node/nodeSocketFactory.ts @@ -5,9 +5,9 @@ import * as net from 'net'; import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; -import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; +import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; -export const nodeWebSocketFactory = new class implements IWebSocketFactory { +export const nodeSocketFactory = new class implements ISocketFactory { connect(host: string, port: number, query: string, callback: IConnectCallback): void { const errorListener = (err: any) => callback(err, undefined); diff --git a/src/vs/platform/request/browser/requestService.ts b/src/vs/platform/request/browser/requestService.ts new file mode 100644 index 00000000000..1cae6c03b31 --- /dev/null +++ b/src/vs/platform/request/browser/requestService.ts @@ -0,0 +1,96 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { canceled } from 'vs/base/common/errors'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ILogService } from 'vs/platform/log/common/log'; +import { assign } from 'vs/base/common/objects'; +import { VSBuffer, bufferToStream } from 'vs/base/common/buffer'; + +/** + * This service exposes the `request` API, while using the global + * or configured proxy settings. + */ +export class RequestService { + + _serviceBrand: any; + + constructor( + @IConfigurationService private readonly configurationService: IConfigurationService, + @ILogService private readonly logService: ILogService + ) { + } + + request(options: IRequestOptions, token: CancellationToken): Promise { + this.logService.trace('RequestService#request', options.url); + + const authorization = this.configurationService.getValue('http.proxyAuthorization'); + if (authorization) { + options.headers = assign(options.headers || {}, { 'Proxy-Authorization': authorization }); + } + + const xhr = new XMLHttpRequest(); + return new Promise((resolve, reject) => { + + xhr.open(options.type || 'GET', options.url || '', true, options.user, options.password); + this.setRequestHeaders(xhr, options); + + xhr.responseType = 'arraybuffer'; + xhr.onerror = e => reject(new Error(xhr.statusText && ('XHR failed: ' + xhr.statusText))); + xhr.onload = (e) => { + resolve({ + res: { + statusCode: xhr.status, + headers: this.getResponseHeaders(xhr) + }, + stream: bufferToStream(VSBuffer.wrap(new Uint8Array(xhr.response))) + }); + }; + xhr.ontimeout = e => reject(new Error(`XHR timeout: ${options.timeout}ms`)); + + if (options.timeout) { + xhr.timeout = options.timeout; + } + + xhr.send(options.data); + + // cancel + token.onCancellationRequested(() => { + xhr.abort(); + reject(canceled()); + }); + }); + } + + private setRequestHeaders(xhr: XMLHttpRequest, options: IRequestOptions): void { + if (options.headers) { + outer: for (let k in options.headers) { + switch (k) { + case 'User-Agent': + case 'Accept-Encoding': + case 'Content-Length': + // unsafe headers + continue outer; + } + xhr.setRequestHeader(k, options.headers[k]); + + } + } + } + + private getResponseHeaders(xhr: XMLHttpRequest): { [name: string]: string } { + const headers: { [name: string]: string } = Object.create(null); + for (const line of xhr.getAllResponseHeaders().split(/\r\n|\n|\r/g)) { + if (line) { + const idx = line.indexOf(':'); + headers[line.substr(0, idx).trim().toLowerCase()] = line.substr(idx + 1).trim(); + } + } + return headers; + } + +} \ No newline at end of file diff --git a/src/vs/platform/request/node/request.ts b/src/vs/platform/request/common/request.ts similarity index 59% rename from src/vs/platform/request/node/request.ts rename to src/vs/platform/request/common/request.ts index a19c75449f8..31e3c314242 100644 --- a/src/vs/platform/request/node/request.ts +++ b/src/vs/platform/request/common/request.ts @@ -4,20 +4,74 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; +import { CancellationToken } from 'vs/base/common/cancellation'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IRequestOptions, IRequestContext } from 'vs/base/node/request'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; -import { CancellationToken } from 'vs/base/common/cancellation'; +import { VSBufferReadableStream, streamToBuffer } from 'vs/base/common/buffer'; export const IRequestService = createDecorator('requestService'); +export interface IHeaders { + [header: string]: string; +} + +export interface IRequestOptions { + type?: string; + url?: string; + user?: string; + password?: string; + headers?: IHeaders; + timeout?: number; + data?: string; + followRedirects?: number; +} + +export interface IRequestContext { + res: { + headers: IHeaders; + statusCode?: number; + }; + stream: VSBufferReadableStream; +} + export interface IRequestService { _serviceBrand: any; request(options: IRequestOptions, token: CancellationToken): Promise; } +function isSuccess(context: IRequestContext): boolean { + return (context.res.statusCode && context.res.statusCode >= 200 && context.res.statusCode < 300) || context.res.statusCode === 1223; +} + +function hasNoContent(context: IRequestContext): boolean { + return context.res.statusCode === 204; +} + +export async function asText(context: IRequestContext): Promise { + if (!isSuccess(context)) { + throw new Error('Server returned ' + context.res.statusCode); + } + if (hasNoContent(context)) { + return null; + } + const buffer = await streamToBuffer(context.stream); + return buffer.toString(); +} + +export async function asJson(context: IRequestContext): Promise { + if (!isSuccess(context)) { + throw new Error('Server returned ' + context.res.statusCode); + } + if (hasNoContent(context)) { + return null; + } + const buffer = await streamToBuffer(context.stream); + return JSON.parse(buffer.toString()); +} + + export interface IHTTPConfiguration { http?: { proxy?: string; @@ -36,7 +90,7 @@ Registry.as(Extensions.Configuration) 'http.proxy': { type: 'string', pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+)(:\\d+)?/?$|^$', - description: localize('proxy', "The proxy setting to use. If not set will be taken from the http_proxy and https_proxy environment variables.") + markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.") }, 'http.proxyStrictSSL': { type: 'boolean', @@ -46,7 +100,7 @@ Registry.as(Extensions.Configuration) 'http.proxyAuthorization': { type: ['null', 'string'], default: null, - description: localize('proxyAuthorization', "The value to send as the 'Proxy-Authorization' header for every network request.") + markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request.") }, 'http.proxySupport': { type: 'string', diff --git a/src/vs/platform/request/common/requestIpc.ts b/src/vs/platform/request/common/requestIpc.ts new file mode 100644 index 00000000000..8f553261707 --- /dev/null +++ b/src/vs/platform/request/common/requestIpc.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; +import { IRequestService, IRequestOptions, IRequestContext, IHeaders } from 'vs/platform/request/common/request'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { VSBuffer, bufferToStream, streamToBuffer } from 'vs/base/common/buffer'; + +type RequestResponse = [ + { + headers: IHeaders; + statusCode?: number; + }, + VSBuffer +]; + +export class RequestChannel implements IServerChannel { + + constructor(private readonly service: IRequestService) { } + + listen(context: any, event: string): Event { + throw new Error('Invalid listen'); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case 'request': return this.service.request(args[0], CancellationToken.None) + .then(async ({ res, stream }) => { + const buffer = await streamToBuffer(stream); + return [{ statusCode: res.statusCode, headers: res.headers }, buffer]; + }); + } + throw new Error('Invalid call'); + } +} + +export class RequestChannelClient { + + _serviceBrand: any; + + constructor(private readonly channel: IChannel) { } + + async request(options: IRequestOptions, token: CancellationToken): Promise { + const [res, buffer] = await this.channel.call('request', [options]); + return { res, stream: bufferToStream(buffer) }; + } + +} diff --git a/src/vs/platform/request/electron-browser/requestService.ts b/src/vs/platform/request/electron-browser/requestService.ts deleted file mode 100644 index 87636c4d4cf..00000000000 --- a/src/vs/platform/request/electron-browser/requestService.ts +++ /dev/null @@ -1,105 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IRequestOptions, IRequestContext, IRequestFunction } from 'vs/base/node/request'; -import { Readable } from 'stream'; -import { RequestService as NodeRequestService } from 'vs/platform/request/node/requestService'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { canceled } from 'vs/base/common/errors'; - -/** - * This service exposes the `request` API, while using the global - * or configured proxy settings. - */ -export class RequestService extends NodeRequestService { - request(options: IRequestOptions, token: CancellationToken): Promise { - return super.request(options, token, xhrRequest); - } -} - -export const xhrRequest: IRequestFunction = (options: IRequestOptions, token: CancellationToken): Promise => { - - const xhr = new XMLHttpRequest(); - return new Promise((resolve, reject) => { - - xhr.open(options.type || 'GET', options.url || '', true, options.user, options.password); - setRequestHeaders(xhr, options); - - xhr.responseType = 'arraybuffer'; - xhr.onerror = e => reject(new Error(xhr.statusText && ('XHR failed: ' + xhr.statusText))); - xhr.onload = (e) => { - resolve({ - res: { - statusCode: xhr.status, - headers: getResponseHeaders(xhr) - }, - stream: new class ArrayBufferStream extends Readable { - - private _buffer: Buffer; - private _offset: number; - private _length: number; - - constructor(arraybuffer: ArrayBuffer) { - super(); - this._buffer = Buffer.from(new Uint8Array(arraybuffer)); - this._offset = 0; - this._length = this._buffer.length; - } - - _read(size: number) { - if (this._offset < this._length) { - this.push(this._buffer.slice(this._offset, (this._offset + size))); - this._offset += size; - } else { - this.push(null); - } - } - - }(xhr.response) - }); - }; - xhr.ontimeout = e => reject(new Error(`XHR timeout: ${options.timeout}ms`)); - - if (options.timeout) { - xhr.timeout = options.timeout; - } - - // TODO: remove any - xhr.send(options.data as any); - - // cancel - token.onCancellationRequested(() => { - xhr.abort(); - reject(canceled()); - }); - }); -}; - -function setRequestHeaders(xhr: XMLHttpRequest, options: IRequestOptions): void { - if (options.headers) { - outer: for (let k in options.headers) { - switch (k) { - case 'User-Agent': - case 'Accept-Encoding': - case 'Content-Length': - // unsafe headers - continue outer; - } - xhr.setRequestHeader(k, options.headers[k]); - - } - } -} - -function getResponseHeaders(xhr: XMLHttpRequest): { [name: string]: string } { - const headers: { [name: string]: string } = Object.create(null); - for (const line of xhr.getAllResponseHeaders().split(/\r\n|\n|\r/g)) { - if (line) { - const idx = line.indexOf(':'); - headers[line.substr(0, idx).trim().toLowerCase()] = line.substr(idx + 1).trim(); - } - } - return headers; -} diff --git a/src/vs/platform/request/electron-main/requestService.ts b/src/vs/platform/request/electron-main/requestService.ts index 72e2847be9e..cd27b9fbf5d 100644 --- a/src/vs/platform/request/electron-main/requestService.ts +++ b/src/vs/platform/request/electron-main/requestService.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IRequestOptions, IRequestContext, request, IRawRequestFunction } from 'vs/base/node/request'; -import { RequestService as NodeRequestService } from 'vs/platform/request/node/requestService'; +import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { RequestService as NodeRequestService, IRawRequestFunction } from 'vs/platform/request/node/requestService'; import { assign } from 'vs/base/common/objects'; import { net } from 'electron'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -16,6 +16,6 @@ function getRawRequest(options: IRequestOptions): IRawRequestFunction { export class RequestService extends NodeRequestService { request(options: IRequestOptions, token: CancellationToken): Promise { - return super.request(options, token, options => request(assign({}, options || {}, { getRawRequest }), token)); + return super.request(assign({}, options || {}, { getRawRequest }), token); } } diff --git a/src/vs/base/node/proxy.ts b/src/vs/platform/request/node/proxy.ts similarity index 97% rename from src/vs/base/node/proxy.ts rename to src/vs/platform/request/node/proxy.ts index 2ef6c6768b2..c5932a7d10b 100644 --- a/src/vs/base/node/proxy.ts +++ b/src/vs/platform/request/node/proxy.ts @@ -5,7 +5,8 @@ import { Url, parse as parseUrl } from 'url'; import { isBoolean } from 'vs/base/common/types'; -import { Agent } from './request'; + +export type Agent = any; function getSystemProxyURI(requestURL: Url): string | null { if (requestURL.protocol === 'http:') { diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index c2858fe6dd0..e0c572277d3 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -3,14 +3,31 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as https from 'https'; +import * as http from 'http'; +import { Stream } from 'stream'; +import { createGunzip } from 'zlib'; +import { parse as parseUrl } from 'url'; import { Disposable } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; -import { IRequestOptions, IRequestContext, IRequestFunction, request } from 'vs/base/node/request'; -import { getProxyAgent } from 'vs/base/node/proxy'; -import { IRequestService, IHTTPConfiguration } from 'vs/platform/request/node/request'; +import { isBoolean, isNumber } from 'vs/base/common/types'; +import { canceled } from 'vs/base/common/errors'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IRequestOptions, IRequestContext, IRequestService, IHTTPConfiguration } from 'vs/platform/request/common/request'; +import { getProxyAgent, Agent } from 'vs/platform/request/node/proxy'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { CancellationToken } from 'vs/base/common/cancellation'; +import { toVSBufferReadableStream } from 'vs/base/common/buffer'; + +export interface IRawRequestFunction { + (options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; +} + +export interface NodeRequestOptions extends IRequestOptions { + agent?: Agent; + strictSSL?: boolean; + getRawRequest?(options: IRequestOptions): IRawRequestFunction; +} /** * This service exposes the `request` API, while using the global @@ -39,21 +56,91 @@ export class RequestService extends Disposable implements IRequestService { this.authorization = config.http && config.http.proxyAuthorization; } - request(options: IRequestOptions, token: CancellationToken, requestFn: IRequestFunction = request): Promise { + async request(options: NodeRequestOptions, token: CancellationToken): Promise { this.logService.trace('RequestService#request', options.url); const { proxyUrl, strictSSL } = this; - const agentPromise = options.agent ? Promise.resolve(options.agent) : Promise.resolve(getProxyAgent(options.url || '', { proxyUrl, strictSSL })); + const agent = options.agent ? options.agent : await getProxyAgent(options.url || '', { proxyUrl, strictSSL }); - return agentPromise.then(agent => { - options.agent = agent; - options.strictSSL = strictSSL; + options.agent = agent; + options.strictSSL = strictSSL; - if (this.authorization) { - options.headers = assign(options.headers || {}, { 'Proxy-Authorization': this.authorization }); + if (this.authorization) { + options.headers = assign(options.headers || {}, { 'Proxy-Authorization': this.authorization }); + } + + return this._request(options, token); + } + + private async getNodeRequest(options: IRequestOptions): Promise { + const endpoint = parseUrl(options.url!); + const module = endpoint.protocol === 'https:' ? await import('https') : await import('http'); + return module.request; + } + + private _request(options: NodeRequestOptions, token: CancellationToken): Promise { + + return new Promise(async (c, e) => { + let req: http.ClientRequest; + + const endpoint = parseUrl(options.url!); + const rawRequest = options.getRawRequest + ? options.getRawRequest(options) + : await this.getNodeRequest(options); + + const opts: https.RequestOptions = { + hostname: endpoint.hostname, + port: endpoint.port ? parseInt(endpoint.port) : (endpoint.protocol === 'https:' ? 443 : 80), + protocol: endpoint.protocol, + path: endpoint.path, + method: options.type || 'GET', + headers: options.headers, + agent: options.agent, + rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true + }; + + if (options.user && options.password) { + opts.auth = options.user + ':' + options.password; } - return requestFn(options, token); + req = rawRequest(opts, (res: http.IncomingMessage) => { + const followRedirects: number = isNumber(options.followRedirects) ? options.followRedirects : 3; + if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && followRedirects > 0 && res.headers['location']) { + this._request(assign({}, options, { + url: res.headers['location'], + followRedirects: followRedirects - 1 + }), token).then(c, e); + } else { + let stream: Stream = res; + + if (res.headers['content-encoding'] === 'gzip') { + stream = stream.pipe(createGunzip()); + } + + c({ res, stream: toVSBufferReadableStream(stream) } as IRequestContext); + } + }); + + req.on('error', e); + + if (options.timeout) { + req.setTimeout(options.timeout); + } + + if (options.data) { + if (typeof options.data === 'string') { + req.write(options.data); + } + } + + req.end(); + + token.onCancellationRequested(() => { + req.abort(); + e(canceled()); + }); }); + } -} + +} \ No newline at end of file diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index 74f8629b401..7e18f2ba09d 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -20,10 +20,10 @@ export class BrowserStorageService extends Disposable implements IStorageService _serviceBrand: ServiceIdentifier; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - get onDidChangeStorage(): Event { return this._onDidChangeStorage.event; } + readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; private readonly _onWillSaveState: Emitter = this._register(new Emitter()); - get onWillSaveState(): Event { return this._onWillSaveState.event; } + readonly onWillSaveState: Event = this._onWillSaveState.event; private globalStorage: IStorage; private workspaceStorage: IStorage; @@ -70,13 +70,17 @@ export class BrowserStorageService extends Disposable implements IStorageService private async doInitialize(payload: IWorkspaceInitializationPayload): Promise { + // Ensure state folder exists + const stateRoot = joinPath(this.environmentService.userRoamingDataHome, 'state'); + await this.fileService.createFolder(stateRoot); + // Workspace Storage - this.workspaceStorageFile = joinPath(this.environmentService.userRoamingDataHome, 'state', `${payload.id}.json`); + this.workspaceStorageFile = joinPath(stateRoot, `${payload.id}.json`); this.workspaceStorage = new Storage(this._register(new FileStorageDatabase(this.workspaceStorageFile, this.fileService))); this._register(this.workspaceStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.WORKSPACE }))); // Global Storage - this.globalStorageFile = joinPath(this.environmentService.userRoamingDataHome, 'state', 'global.json'); + this.globalStorageFile = joinPath(stateRoot, 'global.json'); this.globalStorage = new Storage(this._register(new FileStorageDatabase(this.globalStorageFile, this.fileService))); this._register(this.globalStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.GLOBAL }))); diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index 443cf4a0131..5f6e2b6673f 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -126,7 +126,7 @@ export class InMemoryStorageService extends Disposable implements IStorageServic _serviceBrand = null as any; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - get onDidChangeStorage(): Event { return this._onDidChangeStorage.event; } + readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; readonly onWillSaveState = Event.None; diff --git a/src/vs/platform/storage/node/storageIpc.ts b/src/vs/platform/storage/node/storageIpc.ts index c60779b7bad..aaba475a269 100644 --- a/src/vs/platform/storage/node/storageIpc.ts +++ b/src/vs/platform/storage/node/storageIpc.ts @@ -12,7 +12,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { ILogService } from 'vs/platform/log/common/log'; import { generateUuid } from 'vs/base/common/uuid'; -import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties'; +import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; type Key = string; type Value = string; @@ -32,7 +32,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC private static STORAGE_CHANGE_DEBOUNCE_TIME = 100; private readonly _onDidChangeItems: Emitter = this._register(new Emitter()); - get onDidChangeItems(): Event { return this._onDidChangeItems.event; } + readonly onDidChangeItems: Event = this._onDidChangeItems.event; private whenReady: Promise; @@ -150,7 +150,7 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS _serviceBrand: any; private readonly _onDidChangeItemsExternal: Emitter = this._register(new Emitter()); - get onDidChangeItemsExternal(): Event { return this._onDidChangeItemsExternal.event; } + readonly onDidChangeItemsExternal: Event = this._onDidChangeItemsExternal.event; private onDidChangeItemsOnMainListener: IDisposable; diff --git a/src/vs/platform/storage/node/storageMainService.ts b/src/vs/platform/storage/node/storageMainService.ts index ccb16988860..8c76782626a 100644 --- a/src/vs/platform/storage/node/storageMainService.ts +++ b/src/vs/platform/storage/node/storageMainService.ts @@ -80,10 +80,10 @@ export class StorageMainService extends Disposable implements IStorageMainServic private static STORAGE_NAME = 'state.vscdb'; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - get onDidChangeStorage(): Event { return this._onDidChangeStorage.event; } + readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; private readonly _onWillSaveState: Emitter = this._register(new Emitter()); - get onWillSaveState(): Event { return this._onWillSaveState.event; } + readonly onWillSaveState: Event = this._onWillSaveState.event; get items(): Map { return this.storage.items; } diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index 27d30af0527..caff11a3483 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -25,10 +25,10 @@ export class StorageService extends Disposable implements IStorageService { private static WORKSPACE_META_NAME = 'workspace.json'; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - get onDidChangeStorage(): Event { return this._onDidChangeStorage.event; } + readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; private readonly _onWillSaveState: Emitter = this._register(new Emitter()); - get onWillSaveState(): Event { return this._onWillSaveState.event; } + readonly onWillSaveState: Event = this._onWillSaveState.event; private globalStorage: IStorage; diff --git a/src/vs/platform/storage/test/node/storage.test.ts b/src/vs/platform/storage/test/node/storage.test.ts index 254cb427afa..7c77b9e1c08 100644 --- a/src/vs/platform/storage/test/node/storage.test.ts +++ b/src/vs/platform/storage/test/node/storage.test.ts @@ -12,9 +12,9 @@ import { rimraf, RimRafMode } from 'vs/base/node/pfs'; import { NullLogService } from 'vs/platform/log/common/log'; import { Storage } from 'vs/base/parts/storage/common/storage'; import { URI } from 'vs/base/common/uri'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; diff --git a/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts b/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts new file mode 100644 index 00000000000..3e6c88bd451 --- /dev/null +++ b/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. 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/gdprTypings.ts b/src/vs/platform/telemetry/common/gdprTypings.ts index a4e2dcf8baf..1c988a2c2ce 100644 --- a/src/vs/platform/telemetry/common/gdprTypings.ts +++ b/src/vs/platform/telemetry/common/gdprTypings.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ export interface IPropertyData { - classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData'; + classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData' | 'EndUserPseudonymizedInformation'; purpose: 'PerformanceAndHealth' | 'FeatureInsight' | 'BusinessInsight'; endpoint?: string; isMeasurement?: boolean; diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index e82693979be..847f4856a55 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -38,3 +38,9 @@ export interface ITelemetryService { isOptedIn: boolean; } + +// Keys +export const instanceStorageKey = 'telemetry.instanceId'; +export const currentSessionDateStorageKey = 'telemetry.currentSessionDate'; +export const firstSessionDateStorageKey = 'telemetry.firstSessionDate'; +export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; \ No newline at end of file diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index 30fb12f5f79..576a337237e 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -10,7 +10,7 @@ import { ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils' import { optional } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { cloneAndChange, mixin } from 'vs/base/common/objects'; import { Registry } from 'vs/platform/registry/common/platform'; import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; @@ -19,6 +19,7 @@ export interface ITelemetryServiceConfig { appender: ITelemetryAppender; commonProperties?: Promise<{ [name: string]: any }>; piiPaths?: string[]; + trueMachineId?: string; } export class TelemetryService implements ITelemetryService { @@ -34,7 +35,7 @@ export class TelemetryService implements ITelemetryService { private _userOptIn: boolean; private _enabled: boolean; - private _disposables: IDisposable[] = []; + private readonly _disposables = new DisposableStore(); private _cleanupPatterns: RegExp[] = []; constructor( @@ -68,12 +69,17 @@ export class TelemetryService implements ITelemetryService { this._commonProperties.then(values => { const isHashedId = /^[a-f0-9]+$/i.test(values['common.machineId']); - /* __GDPR__ - "machineIdFallback" : { - "usingFallbackGuid" : { "classification": "SystemMetaData", "purpose": "BusinessInsight", "isMeasurement": true } - } - */ - this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId }); + type MachineIdFallbackClassification = { + usingFallbackGuid: { classification: 'SystemMetaData', purpose: 'BusinessInsight', isMeasurement: true }; + }; + this.publicLog2<{ usingFallbackGuid: boolean }, MachineIdFallbackClassification>('machineIdFallback', { usingFallbackGuid: !isHashedId }); + + if (config.trueMachineId) { + type MachineIdDisambiguationClassification = { + correctedMachineId: { endPoint: 'MacAddressHash', classification: 'EndUserPseudonymizedInformation', purpose: 'FeatureInsight' }; + }; + this.publicLog2<{ correctedMachineId: string }, MachineIdDisambiguationClassification>('machineIdDisambiguation', { correctedMachineId: config.trueMachineId }); + } }); } } @@ -103,7 +109,7 @@ export class TelemetryService implements ITelemetryService { } dispose(): void { - this._disposables = dispose(this._disposables); + this._disposables.dispose(); } publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise { diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 37b4f848681..f8990d64a32 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; @@ -31,17 +33,17 @@ export const NullTelemetryService = new class implements ITelemetryService { export interface ITelemetryAppender { log(eventName: string, data: any): void; - dispose(): Promise | undefined; + flush(): Promise; } export function combinedAppender(...appenders: ITelemetryAppender[]): ITelemetryAppender { return { log: (e, d) => appenders.forEach(a => a.log(e, d)), - dispose: () => Promise.all(appenders.map(a => a.dispose())) + flush: () => Promise.all(appenders.map(a => a.flush())) }; } -export const NullAppender: ITelemetryAppender = { log: () => null, dispose: () => Promise.resolve(null) }; +export const NullAppender: ITelemetryAppender = { log: () => null, flush: () => Promise.resolve(null) }; export class LogAppender implements ITelemetryAppender { @@ -49,7 +51,7 @@ export class LogAppender implements ITelemetryAppender { private commonPropertiesRegex = /^sessionID$|^version$|^timestamp$|^commitHash$|^common\./; constructor(@ILogService private readonly _logService: ILogService) { } - dispose(): Promise { + flush(): Promise { return Promise.resolve(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 5f6f7e3dbe8..f9c012cd344 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); @@ -143,7 +73,7 @@ export class AppInsightsAppender implements ITelemetryAppender { }); } - dispose(): Promise | undefined { + flush(): Promise { if (this._aiClient) { return new Promise(resolve => { this._aiClient!.flush({ @@ -155,6 +85,6 @@ export class AppInsightsAppender implements ITelemetryAppender { }); }); } - return undefined; + return Promise.resolve(undefined); } } diff --git a/src/vs/platform/telemetry/node/telemetry.ts b/src/vs/platform/telemetry/node/telemetry.ts index 31b4ca31d46..626af4983ca 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/telemetry/node/telemetryIpc.ts b/src/vs/platform/telemetry/node/telemetryIpc.ts index 8e1b68eb364..b49a3a23142 100644 --- a/src/vs/platform/telemetry/node/telemetryIpc.ts +++ b/src/vs/platform/telemetry/node/telemetryIpc.ts @@ -37,7 +37,8 @@ export class TelemetryAppenderClient implements ITelemetryAppender { return Promise.resolve(null); } - dispose(): any { + flush(): Promise { // TODO + return Promise.resolve(); } } diff --git a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts index d335c3d170b..d1b83a14146 100644 --- a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts @@ -5,11 +5,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; - -export const instanceStorageKey = 'telemetry.instanceId'; -export const currentSessionDateStorageKey = 'telemetry.currentSessionDate'; -export const firstSessionDateStorageKey = 'telemetry.firstSessionDate'; -export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; +import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> { const result = await resolveCommonProperties(commit, version, machineId, installSourcePath); diff --git a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts index c891f9b894b..92f9d63b15e 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts @@ -84,7 +84,7 @@ suite('AIAdapter', () => { }); teardown(() => { - adapter.dispose(); + adapter.flush(); }); test('Simple event', () => { diff --git a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts index 9f728745344..86a5f5203ed 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -30,7 +30,7 @@ class TestTelemetryAppender implements ITelemetryAppender { return this.events.length; } - public dispose(): Promise { + public flush(): Promise { this.isDisposed = true; return Promise.resolve(null); } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 11cb7598f9c..6f356bfe66b 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -203,7 +203,8 @@ export const widgetShadow = registerColor('widget.shadow', { dark: '#000000', li export const inputBackground = registerColor('input.background', { dark: '#3C3C3C', light: Color.white, hc: Color.black }, nls.localize('inputBoxBackground', "Input box background.")); export const inputForeground = registerColor('input.foreground', { dark: foreground, light: foreground, hc: foreground }, nls.localize('inputBoxForeground', "Input box foreground.")); export const inputBorder = registerColor('input.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('inputBoxBorder', "Input box border.")); -export const inputActiveOptionBorder = registerColor('inputOption.activeBorder', { dark: '#007ACC', light: '#007ACC', hc: activeContrastBorder }, nls.localize('inputBoxActiveOptionBorder', "Border color of activated options in input fields.")); +export const inputActiveOptionBorder = registerColor('inputOption.activeBorder', { dark: '#007ACC00', light: '#007ACC00', hc: contrastBorder }, nls.localize('inputBoxActiveOptionBorder', "Border color of activated options in input fields.")); +export const inputActiveOptionBackground = registerColor('inputOption.activeBackground', { dark: transparent(focusBorder, 0.5), light: transparent(focusBorder, 0.3), hc: null }, nls.localize('inputOption.activeBackground', "Background color of activated options in input fields.")); export const inputPlaceholderForeground = registerColor('input.placeholderForeground', { light: transparent(foreground, 0.5), dark: transparent(foreground, 0.5), hc: transparent(foreground, 0.7) }, nls.localize('inputPlaceholderForeground', "Input box foreground color for placeholder text.")); export const inputValidationInfoBackground = registerColor('inputValidation.infoBackground', { dark: '#063B49', light: '#D6ECF2', hc: Color.black }, nls.localize('inputValidationInfoBackground', "Input validation background color for information severity.")); @@ -271,8 +272,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/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index d04b8bd3c8f..75245df2d1e 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; +import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; @@ -59,11 +59,13 @@ export function attachStyler(themeService: IThemeServic export interface ICheckboxStyleOverrides extends IStyleOverrides { inputActiveOptionBorderColor?: ColorIdentifier; + inputActiveOptionBackgroundColor?: ColorIdentifier; } export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: ICheckboxStyleOverrides): IDisposable { return attachStyler(themeService, { - inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder + inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder, + inputActiveOptionBackground: (style && style.inputActiveOptionBackgroundColor) || inputActiveOptionBackground } as ICheckboxStyleOverrides, widget); } @@ -85,6 +87,7 @@ export interface IInputBoxStyleOverrides extends IStyleOverrides { inputForeground?: ColorIdentifier; inputBorder?: ColorIdentifier; inputActiveOptionBorder?: ColorIdentifier; + inputActiveOptionBackground?: ColorIdentifier; inputValidationInfoBorder?: ColorIdentifier; inputValidationInfoBackground?: ColorIdentifier; inputValidationInfoForeground?: ColorIdentifier; @@ -146,6 +149,7 @@ export function attachFindInputBoxStyler(widget: IThemable, themeService: ITheme inputForeground: (style && style.inputForeground) || inputForeground, inputBorder: (style && style.inputBorder) || inputBorder, inputActiveOptionBorder: (style && style.inputActiveOptionBorder) || inputActiveOptionBorder, + inputActiveOptionBackground: (style && style.inputActiveOptionBackground) || inputActiveOptionBackground, inputValidationInfoBorder: (style && style.inputValidationInfoBorder) || inputValidationInfoBorder, inputValidationInfoBackground: (style && style.inputValidationInfoBackground) || inputValidationInfoBackground, inputValidationInfoForeground: (style && style.inputValidationInfoForeground) || inputValidationInfoForeground, diff --git a/src/vs/platform/update/electron-browser/updateService.ts b/src/vs/platform/update/electron-browser/updateService.ts index 023ea3ea7da..952c39cdbed 100644 --- a/src/vs/platform/update/electron-browser/updateService.ts +++ b/src/vs/platform/update/electron-browser/updateService.ts @@ -14,7 +14,7 @@ export class UpdateService implements IUpdateService { _serviceBrand: ServiceIdentifier; private _onStateChange = new Emitter(); - get onStateChange(): Event { return this._onStateChange.event; } + readonly onStateChange: Event = this._onStateChange.event; private _state: State = State.Uninitialized; get state(): State { return this._state; } diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index fcca3cbfb9f..2a1240b1eb9 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -11,13 +11,17 @@ import product from 'vs/platform/product/node/product'; import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; -import { IRequestService } from 'vs/platform/request/node/request'; +import { IRequestService } from 'vs/platform/request/common/request'; import { CancellationToken } from 'vs/base/common/cancellation'; 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; @@ -27,7 +31,7 @@ export abstract class AbstractUpdateService implements IUpdateService { private _state: State = State.Uninitialized; private _onStateChange = new Emitter(); - get onStateChange(): Event { return this._onStateChange.event; } + readonly onStateChange: Event = this._onStateChange.event; get state(): State { return this._state; diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index 4427e2a75eb..da534803b83 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -13,8 +13,8 @@ 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 { IRequestService } from 'vs/platform/request/node/request'; +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 38b022755d9..07eaf22cb09 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -6,13 +6,12 @@ import product from 'vs/platform/product/node/product'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; -import { IRequestService } from 'vs/platform/request/node/request'; import { State, IUpdate, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; 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 { asJson } from 'vs/base/node/request'; +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'; @@ -41,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 { @@ -60,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 33dac322927..54f63ca59e4 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 { @@ -21,7 +22,7 @@ abstract class AbstractUpdateService2 implements IUpdateService { private _state: State = State.Uninitialized; private _onStateChange = new Emitter(); - get onStateChange(): Event { return this._onStateChange.event; } + readonly onStateChange: Event = this._onStateChange.event; get state(): State { return this._state; @@ -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 8467f908dc6..bd7a3d35f7c 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -9,20 +9,21 @@ import * as pfs from 'vs/base/node/pfs'; import { memoize } from 'vs/base/common/decorators'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; -import { IRequestService } from 'vs/platform/request/node/request'; import product from 'vs/platform/product/node/product'; import { State, IUpdate, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; 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 { download, asJson } from 'vs/base/node/request'; +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'; import { spawn } from 'child_process'; import { shell } from 'electron'; import { CancellationToken } from 'vs/base/common/cancellation'; import { timeout } from 'vs/base/common/async'; +import { IFileService } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; async function pollUntil(fn: () => boolean, millis = 1000): Promise { while (!fn()) { @@ -64,7 +65,8 @@ export class Win32UpdateService extends AbstractUpdateService { @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, @IRequestService requestService: IRequestService, - @ILogService logService: ILogService + @ILogService logService: ILogService, + @IFileService private readonly fileService: IFileService ) { super(lifecycleService, configurationService, environmentService, requestService, logService); @@ -112,12 +114,7 @@ export class Win32UpdateService extends AbstractUpdateService { const updateType = getUpdateType(); 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)); return Promise.resolve(null); @@ -142,7 +139,7 @@ export class Win32UpdateService extends AbstractUpdateService { const downloadPath = `${updatePackagePath}.tmp`; return this.requestService.request({ url }, CancellationToken.None) - .then(context => download(downloadPath, context)) + .then(context => this.fileService.writeFile(URI.file(downloadPath), context.stream)) .then(hash ? () => checksum(downloadPath, update.hash) : () => undefined) .then(() => pfs.rename(downloadPath, updatePackagePath)) .then(() => updatePackagePath); @@ -166,12 +163,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 d9e25ebfa2c..0339be71c36 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -156,7 +156,7 @@ export interface IWindowsService { openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise; getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>; getWindowCount(): Promise; - log(severity: string, ...messages: string[]): Promise; + log(severity: string, args: string[]): Promise; showItemInFolder(path: URI): Promise; getActiveWindowId(): Promise; @@ -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-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts index 34ec58fc49a..228dfd98ba2 100644 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -226,8 +226,8 @@ export class WindowsService implements IWindowsService { return this.channel.call('getWindowCount'); } - log(severity: string, ...messages: string[]): Promise { - return this.channel.call('log', [severity, messages]); + log(severity: string, args: string[]): Promise { + return this.channel.call('log', [severity, args]); } showItemInFolder(path: URI): Promise { @@ -257,4 +257,4 @@ export class WindowsService implements IWindowsService { resolveProxy(windowId: number, url: string): Promise { return Promise.resolve(this.channel.call('resolveProxy', [windowId, url])); } -} \ No newline at end of file +} diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index cb72892f40e..3e64f5f5d0b 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 f74d5c79849..c33bbb42b8a 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 }); @@ -333,7 +334,7 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH return this.windowsMainService.getWindows().length; } - async log(severity: string, ...messages: string[]): Promise { + async log(severity: string, args: string[]): Promise { let consoleFn = console.log; switch (severity) { @@ -348,7 +349,7 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH break; } - consoleFn(...messages); + consoleFn.call(console, ...args); } async showItemInFolder(resource: URI): Promise { @@ -459,10 +460,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/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 58107e613f2..54d6757842a 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -31,7 +31,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain private readonly untitledWorkspacesHome: URI; // local URI that contains all untitled workspaces private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter()); - get onUntitledWorkspaceDeleted(): Event { return this._onUntitledWorkspaceDeleted.event; } + readonly onUntitledWorkspaceDeleted: Event = this._onUntitledWorkspaceDeleted.event; constructor( @IEnvironmentService private readonly environmentService: IEnvironmentService, diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 786439397ef..65892f8b976 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3826,7 +3826,7 @@ declare module 'vscode' { /** * Provide selection ranges for the given positions. * - * Selection ranges should be computed individually and independend for each position. The editor will merge + * Selection ranges should be computed individually and independent for each position. The editor will merge * and deduplicate ranges but providers must return hierarchies of selection ranges so that a range * is [contained](#Range.contains) by its parent. * diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 217471a484d..8eac40ea882 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -94,6 +94,12 @@ declare module 'vscode' { constructor(host: string, port: number); } + export interface ResolvedOptions { + extensionHostEnv?: { [key: string]: string | null }; + } + + export type ResolverResult = ResolvedAuthority & ResolvedOptions; + export class RemoteAuthorityResolverError extends Error { static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError; static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError; @@ -102,7 +108,7 @@ declare module 'vscode' { } export interface RemoteAuthorityResolver { - resolve(authority: string, context: RemoteAuthorityResolverContext): ResolvedAuthority | Thenable; + resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable; } export interface ResourceLabelFormatter { @@ -559,6 +565,22 @@ declare module 'vscode' { //#endregion + //#region Joh: onDidExecuteCommand + + export interface CommandExecutionEvent { + command: string; + arguments: any[]; + } + + export namespace commands { + /** + * An event that is emitted when a [command](#Command) is executed. + */ + export const onDidExecuteCommand: Event; + } + + //#endregion + //#region Joh: decorations //todo@joh -> make class @@ -713,54 +735,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 @@ -842,7 +816,7 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText) is triggered that will fire the * [TerminalRenderer.onDidAcceptInput](#TerminalRenderer.onDidAcceptInput) event. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Create a terminal renderer, show it and write hello world in red * ```typescript @@ -854,7 +828,7 @@ declare module 'vscode' { export interface TerminalRenderer { /** * The name of the terminal, this will appear in the terminal selector. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ name: string; @@ -863,7 +837,7 @@ declare module 'vscode' { * a value smaller than the maximum value, if this is undefined the terminal will auto fit * to the maximum value [maximumDimensions](TerminalRenderer.maximumDimensions). * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Override the dimensions of a TerminalRenderer to 20 columns and 10 rows * ```typescript @@ -881,14 +855,14 @@ declare module 'vscode' { * Listen to [onDidChangeMaximumDimensions](TerminalRenderer.onDidChangeMaximumDimensions) * to get notified when this value changes. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly maximumDimensions: TerminalDimensions | undefined; /** * The corresponding [Terminal](#Terminal) for this TerminalRenderer. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly terminal: Terminal; @@ -897,7 +871,7 @@ declare module 'vscode' { * text to the underlying _process_, this will write the text to the terminal itself. * * @param text The text to write. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Write red text to the terminal * ```typescript @@ -916,7 +890,7 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their * corresponding VT sequence representation. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Simulate interaction with the terminal from an outside extension or a * workbench command such as `workbench.action.terminal.runSelectedText` @@ -934,7 +908,7 @@ declare module 'vscode' { * An event which fires when the [maximum dimensions](#TerminalRenderer.maximumDimensions) of * the terminal renderer change. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly onDidChangeMaximumDimensions: Event; } @@ -944,60 +918,60 @@ declare module 'vscode' { * Create a [TerminalRenderer](#TerminalRenderer). * * @param name The name of the terminal renderer, this shows up in the terminal selector. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ export function createTerminalRenderer(name: string): TerminalRenderer; } //#endregion - //#region Terminal virtual process + //#region Extension terminals export namespace window { /** - * Creates a [Terminal](#Terminal) where an extension acts as the process. + * Creates a [Terminal](#Terminal) where an extension controls the teerminal. * - * @param options A [TerminalVirtualProcessOptions](#TerminalVirtualProcessOptions) object describing the - * characteristics of the new terminal. + * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * the characteristics of the new terminal. * @return A new Terminal. */ - export function createTerminal(options: TerminalVirtualProcessOptions): Terminal; + export function createTerminal(options: ExtensionTerminalOptions): Terminal; } /** * Value-object describing what options a virtual process terminal should use. */ - export interface TerminalVirtualProcessOptions { + export interface ExtensionTerminalOptions { /** * A human-readable string which will be used to represent the terminal in the UI. */ name: string; /** - * An implementation of [TerminalVirtualProcess](#TerminalVirtualProcess) that allows an - * extension to act as a terminal's backing process. + * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * control a terminal. */ - virtualProcess: TerminalVirtualProcess; + pty: Pseudoterminal; } /** - * Defines the interface of a terminal virtual process, enabling extensions to act as a process - * in the terminal. + * Defines the interface of a terminal pty, enabling extensions to control a terminal. */ - interface TerminalVirtualProcess { + interface Pseudoterminal { /** * An event that when fired will write data to the terminal. Unlike - * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_, - * this will write the text to the terminal itself. + * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_ + * (the pty "slave"), this will write the text to the terminal itself (the pty "master"). * * **Example:** Write red text to the terminal * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { - * onDidWrite: writeEmitter.event + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * close: () => {} * }; - * vscode.window.createTerminal({ name: 'My terminal', virtualProcess }); - * writeEmitter.fire('\x1b[31mHello world\x1b[0m'); + * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` * * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk @@ -1011,57 +985,82 @@ declare module 'vscode' { * An event that when fired allows overriding the [dimensions](#Terminal.dimensions) of the * terminal. Note that when set the overridden dimensions will only take effect when they * are lower than the actual dimensions of the terminal (ie. there will never be a scroll - * bar). Set to `undefined` for the terminal to go back to the regular dimensions. + * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to + * the size of the panel). * * **Example:** Override the dimensions of a terminal to 20 columns and 10 rows * ```typescript * const dimensionsEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * onDidOverrideDimensions: dimensionsEmitter.event + * onDidOverrideDimensions: dimensionsEmitter.event, + * open: () => { + * dimensionsEmitter.fire({ + * columns: 20, + * rows: 10 + * }); + * }, + * close: () => {} * }; - * vscode.window.createTerminal({ name: 'My terminal', virtualProcess }); - * dimensionsEmitter.fire({ - * columns: 20, - * rows: 10 - * }); + * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` */ onDidOverrideDimensions?: Event; /** - * An event that when fired will exit the process with an exit code, this will behave the - * same for a virtual process as when a regular process exits with an exit code. + * An event that when fired will signal that the pty is closed and dispose of the terminal. * - * **Example:** Exit with an exit code of `0` if the y key is pressed, otherwise `1`. + * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const exitEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const closeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * input: data => exitEmitter.fire(data === 'y' ? 0 : 1) + * onDidClose: closeEmitter.event, + * open: () => writeEmitter.fire('Press y to exit successfully'), + * close: () => {} + * handleInput: { + * if (data !== 'y') { + * vscode.window.showInformationMessage('Something went wrong'); + * } + * data => closeEmitter.fire(); + * } * }; - * vscode.window.createTerminal({ name: 'Exit example', virtualProcess }); - * writeEmitter.fire('Press y to exit successfully'); + * vscode.window.createTerminal({ name: 'Exit example', pty }); */ - onDidExit?: Event; + onDidClose?: Event; /** - * Implement to handle keystrokes in the terminal or when an extension calls - * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their - * corresponding VT sequence representation. + * Implement to handle when the pty is open and ready to start firing events. * - * @param data The sent data. + * @param initialDimensions The dimensions of the terminal, this will be undefined if the + * terminal panel has not been opened before this is called. + */ + open(initialDimensions: TerminalDimensions | undefined): void; + + /** + * Implement to handle when the terminal is closed by an act of the user. + */ + close(): void; + + /** + * Implement to handle incoming keystrokes in the terminal or when an extension calls + * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into + * their corresponding VT sequence representation. + * + * @param data The incoming data. * * **Example:** Echo input in the terminal. The sequence for enter (`\r`) is translated to * CRLF to go to a new line and move the cursor to the start of the line. * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, + * open: () => {}, + * close: () => {}, * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) * }; - * vscode.window.createTerminal({ name: 'Local echo', virtualProcess }); + * vscode.window.createTerminal({ name: 'Local echo', pty }); * ``` */ handleInput?(data: string): void; @@ -1075,16 +1074,6 @@ declare module 'vscode' { * @param dimensions The new dimensions. */ setDimensions?(dimensions: TerminalDimensions): void; - - /** - * Implement to handle when the terminal shuts down by an act of the user. - */ - shutdown?(): void; - - /** - * Implement to handle when the terminal is ready to start firing events. - */ - start?(): void; } //#endregion @@ -1167,6 +1156,7 @@ declare module 'vscode' { } //#endregion + //#region CustomExecution /** * Class used to execute an extension callback as a task. */ @@ -1190,16 +1180,17 @@ declare module 'vscode' { */ export class CustomExecution2 { /** - * @param process The [TerminalVirtualProcess](#TerminalVirtualProcess) to be used by the task to display output. + * @param process The [Pseudotrminal](#Pseudoterminal) to be used by the task to display output. * @param callback The callback that will be called when the task is started by a user. */ - constructor(callback: (thisArg?: any) => Thenable); + constructor(callback: (thisArg?: any) => Thenable); /** - * The callback used to execute the task. Cancellation should be handled using the shutdown method of [TerminalVirtualProcess](#TerminalVirtualProcess). - * When the task is complete, onDidExit should be fired on the TerminalVirtualProcess with the exit code with '0' for success and a non-zero value for failure. + * The callback used to execute the task. Cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). */ - callback: (thisArg?: any) => Thenable; + callback: (thisArg?: any) => Thenable; } /** @@ -1225,6 +1216,7 @@ declare module 'vscode' { */ execution2?: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2; } + //#endregion //#region Tasks export interface TaskPresentationOptions { @@ -1288,14 +1280,41 @@ declare module 'vscode' { export interface Webview { /** * Convert a uri for the local file system to one that can be used inside webviews. + * + * Webviews cannot directly load resoruces from the workspace or local file system using `file:` uris. The + * `toWebviewResource` function takes a local `file:` uri and converts it into a uri that can be used inside of + * a webview to load the same resource: + * + * ```ts + * webview.html = `` + * ``` */ toWebviewResource(localResource: Uri): Uri; /** - * Content security policy rule for webview resources. + * Content security policy source for webview resources. + * + * This is origin used in a content security policy rule: + * + * ``` + * img-src https: ${webview.cspSource} ...; + * ```` */ readonly cspSource: string; } //#endregion + + //#region Deprecated support + + export enum DiagnosticTag { + /** + * Deprecated or obsolete code. + * + * Diagnostics with this tag are rendered with a strike through. + */ + Deprecated = 2, + } + + //#endregion } diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index dca4efc3835..2905c524113 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -48,6 +48,7 @@ import './mainThreadStorage'; import './mainThreadTelemetry'; import './mainThreadTerminalService'; import './mainThreadTreeViews'; +import './mainThreadDownloadService'; import './mainThreadUrls'; import './mainThreadWindow'; import './mainThreadWebview'; diff --git a/src/vs/workbench/api/browser/mainThreadClipboard.ts b/src/vs/workbench/api/browser/mainThreadClipboard.ts index 78df4a034b0..85c041c5b6e 100644 --- a/src/vs/workbench/api/browser/mainThreadClipboard.ts +++ b/src/vs/workbench/api/browser/mainThreadClipboard.ts @@ -20,11 +20,10 @@ export class MainThreadClipboard implements MainThreadClipboardShape { } $readText(): Promise { - return Promise.resolve(this._clipboardService.readText()); + return this._clipboardService.readText(); } $writeText(value: string): Promise { - this._clipboardService.writeText(value); - return Promise.resolve(); + return this._clipboardService.writeText(value); } } diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index e52a8969269..48938ad1f5b 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 @@ -88,7 +88,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { const disposables = new DisposableStore(); - const webview = this._webviewService.createWebview({ + const webview = this._webviewService.createWebview('' + handle, { enableFindWidget: false, allowSvgs: false, extension: { id: extensionId, location: URI.revive(extensionLocation) } @@ -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/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts index 2f4d043f048..25dc1138055 100644 --- a/src/vs/workbench/api/browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCommands.ts @@ -15,6 +15,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { private readonly _commandRegistrations = new Map(); private readonly _generateCommandsDocumentationRegistration: IDisposable; private readonly _proxy: ExtHostCommandsShape; + private _onDidExecuteCommandListener?: IDisposable; constructor( extHostContext: IExtHostContext, @@ -77,6 +78,19 @@ export class MainThreadCommands implements MainThreadCommandsShape { return this._commandService.executeCommand(id, ...args); } + $registerCommandListener() { + if (!this._onDidExecuteCommandListener) { + this._onDidExecuteCommandListener = this._commandService.onDidExecuteCommand(command => this._proxy.$handleDidExecuteCommand(command)); + } + } + + $unregisterCommandListener() { + if (this._onDidExecuteCommandListener) { + this._onDidExecuteCommandListener.dispose(); + this._onDidExecuteCommandListener = undefined; + } + } + $getCommands(): Promise { return Promise.resolve([...CommandsRegistry.getCommands().keys()]); } diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 7bce8f98dee..2580f438473 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -57,7 +57,7 @@ export class MainThreadCommentThread implements modes.CommentThread { } private _onDidChangeLabel = new Emitter(); - get onDidChangeLabel(): Event { return this._onDidChangeLabel.event; } + readonly onDidChangeLabel: Event = this._onDidChangeLabel.event; private _comments: modes.Comment[] | undefined; @@ -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 af983213492..1d7a7723404 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 { @@ -40,7 +40,7 @@ export class MainThreadConsole implements MainThreadConsoleShape { // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(entry.severity, ...parse(entry).args); + this._windowsService.log(entry.severity, parse(entry).args); } // Broadcast to other windows if we are in development mode diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index 7386b69e611..85039369466 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -5,7 +5,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI as uri } from 'vs/base/common/uri'; -import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto @@ -71,8 +71,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb return Promise.resolve(this._proxy.$substituteVariables(folder ? folder.uri : undefined, config)); } - runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { - return Promise.resolve(this._proxy.$runInTerminal(args, config)); + runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { + return Promise.resolve(this._proxy.$runInTerminal(args)); } // RPC methods (MainThreadDebugServiceShape) diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index adfef42555b..30c8a366e90 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -76,7 +76,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { private readonly _toDispose = new DisposableStore(); private _modelToDisposeMap: { [modelUrl: string]: IDisposable; }; private readonly _proxy: ExtHostDocumentsShape; - private readonly _modelIsSynced: { [modelId: string]: boolean; }; + private readonly _modelIsSynced = new Set(); private _modelReferenceCollection = new BoundModelReferenceCollection(); constructor( @@ -98,7 +98,6 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { this._environmentService = environmentService; this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments); - this._modelIsSynced = {}; this._toDispose.add(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this))); this._toDispose.add(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this))); @@ -144,7 +143,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { return; } const modelUrl = model.uri; - this._modelIsSynced[modelUrl.toString()] = true; + this._modelIsSynced.add(modelUrl.toString()); this._modelToDisposeMap[modelUrl.toString()] = model.onDidChangeContent((e) => { this._proxy.$acceptModelChanged(modelUrl, e, this._textFileService.isDirty(modelUrl)); }); @@ -153,7 +152,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void { let { model, oldModeId } = event; const modelUrl = model.uri; - if (!this._modelIsSynced[modelUrl.toString()]) { + if (!this._modelIsSynced.has(modelUrl.toString())) { return; } this._proxy.$acceptModelModeChanged(model.uri, oldModeId, model.getLanguageIdentifier().language); @@ -161,10 +160,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { private _onModelRemoved(modelUrl: URI): void { const strModelUrl = modelUrl.toString(); - if (!this._modelIsSynced[strModelUrl]) { + if (!this._modelIsSynced.has(strModelUrl)) { return; } - delete this._modelIsSynced[strModelUrl]; + this._modelIsSynced.delete(strModelUrl); this._modelToDisposeMap[strModelUrl].dispose(); delete this._modelToDisposeMap[strModelUrl]; } @@ -195,7 +194,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { return promise.then(success => { if (!success) { return Promise.reject(new Error('cannot open ' + uri.toString())); - } else if (!this._modelIsSynced[uri.toString()]) { + } else if (!this._modelIsSynced.has(uri.toString())) { return Promise.reject(new Error('cannot open ' + uri.toString() + '. Detail: Files above 50MB cannot be synchronized with extensions.')); } else { return undefined; @@ -236,7 +235,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { }).then(model => { const resource = model.getResource(); - if (!this._modelIsSynced[resource.toString()]) { + if (!this._modelIsSynced.has(resource.toString())) { throw new Error(`expected URI ${resource.toString()} to have come to LIFE`); } diff --git a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts index 575e7448869..804349ee484 100644 --- a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts @@ -306,7 +306,7 @@ export class MainThreadDocumentsAndEditors { private readonly _toDispose = new DisposableStore(); private readonly _proxy: ExtHostDocumentsAndEditorsShape; - private _textEditors = <{ [id: string]: MainThreadTextEditor }>Object.create(null); + private readonly _textEditors = new Map(); private _onTextEditorAdd = new Emitter(); private _onTextEditorRemove = new Emitter(); @@ -368,16 +368,16 @@ export class MainThreadDocumentsAndEditors { const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.editor.getModel(), apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService); - this._textEditors[apiEditor.id] = mainThreadEditor; + this._textEditors.set(apiEditor.id, mainThreadEditor); addedEditors.push(mainThreadEditor); } // removed editors for (const { id } of delta.removedEditors) { - const mainThreadEditor = this._textEditors[id]; + const mainThreadEditor = this._textEditors.get(id); if (mainThreadEditor) { mainThreadEditor.dispose(); - delete this._textEditors[id]; + this._textEditors.delete(id); removedEditors.push(id); } } @@ -448,16 +448,16 @@ export class MainThreadDocumentsAndEditors { return undefined; } - findTextEditorIdFor(editor: IWorkbenchEditor): string | undefined { - for (const id in this._textEditors) { - if (this._textEditors[id].matches(editor)) { + findTextEditorIdFor(inputEditor: IWorkbenchEditor): string | undefined { + for (const [id, editor] of this._textEditors) { + if (editor.matches(inputEditor)) { return id; } } return undefined; } - getEditor(id: string): MainThreadTextEditor { - return this._textEditors[id]; + getEditor(id: string): MainThreadTextEditor | undefined { + return this._textEditors.get(id); } } diff --git a/src/vs/workbench/api/browser/mainThreadDownloadService.ts b/src/vs/workbench/api/browser/mainThreadDownloadService.ts new file mode 100644 index 00000000000..8b64b910337 --- /dev/null +++ b/src/vs/workbench/api/browser/mainThreadDownloadService.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { MainContext, IExtHostContext, MainThreadDownloadServiceShape } from 'vs/workbench/api/common/extHost.protocol'; +import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; +import { IDownloadService } from 'vs/platform/download/common/download'; +import { UriComponents, URI } from 'vs/base/common/uri'; + +@extHostNamedCustomer(MainContext.MainThreadDownloadService) +export class MainThreadDownloadService extends Disposable implements MainThreadDownloadServiceShape { + + constructor( + extHostContext: IExtHostContext, + @IDownloadService private readonly downloadService: IDownloadService + ) { + super(); + } + + $download(uri: UriComponents, to: UriComponents): Promise { + return this.downloadService.download(URI.revive(uri), URI.revive(to)); + } + +} \ No newline at end of file diff --git a/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts index 25f4a8e1e9c..8601055aeeb 100644 --- a/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -15,7 +15,7 @@ import { ISelection } from 'vs/editor/common/core/selection'; import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon'; import { ISingleEditOperation } from 'vs/editor/common/model'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { IEditorOptions, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors'; @@ -112,7 +112,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { // --- from extension host process - $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise { + async $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise { const uri = URI.revive(resource); const editorOptions: ITextEditorOptions = { @@ -121,91 +121,95 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { selection: options.selection }; - const input = { + const input: IResourceInput = { resource: uri, options: editorOptions }; - return this._editorService.openEditor(input, viewColumnToEditorGroup(this._editorGroupService, options.position)).then(editor => { - if (!editor) { - return undefined; - } - return this._documentsAndEditors.findTextEditorIdFor(editor); - }); + const editor = await this._editorService.openEditor(input, viewColumnToEditorGroup(this._editorGroupService, options.position)); + if (!editor) { + return undefined; + } + return this._documentsAndEditors.findTextEditorIdFor(editor); } - $tryShowEditor(id: string, position?: EditorViewColumn): Promise { + async $tryShowEditor(id: string, position?: EditorViewColumn): Promise { const mainThreadEditor = this._documentsAndEditors.getEditor(id); if (mainThreadEditor) { const model = mainThreadEditor.getModel(); - return this._editorService.openEditor({ + await this._editorService.openEditor({ resource: model.uri, options: { preserveFocus: false } - }, viewColumnToEditorGroup(this._editorGroupService, position)).then(() => { return; }); + }, viewColumnToEditorGroup(this._editorGroupService, position)); + return; } - return Promise.resolve(); } - $tryHideEditor(id: string): Promise { + async $tryHideEditor(id: string): Promise { const mainThreadEditor = this._documentsAndEditors.getEditor(id); if (mainThreadEditor) { const editors = this._editorService.visibleControls; for (let editor of editors) { if (mainThreadEditor.matches(editor)) { - return editor.group.closeEditor(editor.input).then(() => { return; }); + return editor.group.closeEditor(editor.input); } } } - return Promise.resolve(); } $trySetSelections(id: string, selections: ISelection[]): Promise { - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - this._documentsAndEditors.getEditor(id).setSelections(selections); + editor.setSelections(selections); return Promise.resolve(undefined); } $trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): Promise { key = `${this._instanceId}-${key}`; - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - this._documentsAndEditors.getEditor(id).setDecorations(key, ranges); + editor.setDecorations(key, ranges); return Promise.resolve(undefined); } $trySetDecorationsFast(id: string, key: string, ranges: number[]): Promise { key = `${this._instanceId}-${key}`; - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - this._documentsAndEditors.getEditor(id).setDecorationsFast(key, ranges); + editor.setDecorationsFast(key, ranges); return Promise.resolve(undefined); } $tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): Promise { - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - this._documentsAndEditors.getEditor(id).revealRange(range, revealType); + editor.revealRange(range, revealType); return Promise.resolve(); } $trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Promise { - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - this._documentsAndEditors.getEditor(id).setConfiguration(options); + editor.setConfiguration(options); return Promise.resolve(undefined); } $tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Promise { - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - return Promise.resolve(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts)); + return Promise.resolve(editor.applyEdits(modelVersionId, edits, opts)); } $tryApplyWorkspaceEdit(dto: WorkspaceEditDto): Promise { @@ -214,10 +218,11 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { } $tryInsertSnippet(id: string, template: string, ranges: readonly IRange[], opts: IUndoStopOptions): Promise { - if (!this._documentsAndEditors.getEditor(id)) { + const editor = this._documentsAndEditors.getEditor(id); + if (!editor) { return Promise.reject(disposed(`TextEditor(${id})`)); } - return Promise.resolve(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts)); + return Promise.resolve(editor.insertSnippet(template, ranges, opts)); } $registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void { diff --git a/src/vs/workbench/api/browser/mainThreadExtensionService.ts b/src/vs/workbench/api/browser/mainThreadExtensionService.ts index 3089f46e97b..41ab45643b9 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/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index d54e01d9a9b..75af9eebf01 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -27,7 +27,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha private readonly _proxy: ExtHostLanguageFeaturesShape; private readonly _modeService: IModeService; - private readonly _registrations: { [handle: number]: IDisposable; } = Object.create(null); + private readonly _registrations = new Map(); constructor( extHostContext: IExtHostContext, @@ -38,16 +38,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha } dispose(): void { - for (const key in this._registrations) { - this._registrations[key].dispose(); + for (const registration of this._registrations.values()) { + registration.dispose(); } + this._registrations.clear(); } $unregister(handle: number): void { - const registration = this._registrations[handle]; + const registration = this._registrations.get(handle); if (registration) { registration.dispose(); - delete this._registrations[handle]; + this._registrations.delete(handle); } } @@ -122,12 +123,12 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- outline $registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void { - this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, { + this._registrations.set(handle, modes.DocumentSymbolProviderRegistry.register(selector, { displayName, provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise => { return this._proxy.$provideDocumentSymbols(handle, model.uri, token); } - }); + })); } // --- code lens @@ -153,15 +154,15 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha if (typeof eventHandle === 'number') { const emitter = new Emitter(); - this._registrations[eventHandle] = emitter; + this._registrations.set(eventHandle, emitter); provider.onDidChange = emitter.event; } - this._registrations[handle] = modes.CodeLensProviderRegistry.register(selector, provider); + this._registrations.set(handle, modes.CodeLensProviderRegistry.register(selector, provider)); } $emitCodeLensEvent(eventHandle: number, event?: any): void { - const obj = this._registrations[eventHandle]; + const obj = this._registrations.get(eventHandle); if (obj instanceof Emitter) { obj.fire(event); } @@ -170,71 +171,71 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- declaration $registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.DefinitionProviderRegistry.register(selector, { + this._registrations.set(handle, modes.DefinitionProviderRegistry.register(selector, { provideDefinition: (model, position, token): Promise => { return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto); } - }); + })); } $registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.DeclarationProviderRegistry.register(selector, { + this._registrations.set(handle, modes.DeclarationProviderRegistry.register(selector, { provideDeclaration: (model, position, token) => { return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto); } - }); + })); } $registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.ImplementationProviderRegistry.register(selector, { + this._registrations.set(handle, modes.ImplementationProviderRegistry.register(selector, { provideImplementation: (model, position, token): Promise => { return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto); } - }); + })); } $registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, { + this._registrations.set(handle, modes.TypeDefinitionProviderRegistry.register(selector, { provideTypeDefinition: (model, position, token): Promise => { return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto); } - }); + })); } // --- extra info $registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.HoverProviderRegistry.register(selector, { + this._registrations.set(handle, modes.HoverProviderRegistry.register(selector, { provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => { return this._proxy.$provideHover(handle, model.uri, position, token); } - }); + })); } // --- occurrences $registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(selector, { + this._registrations.set(handle, modes.DocumentHighlightProviderRegistry.register(selector, { provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => { return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token); } - }); + })); } // --- references $registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.ReferenceProviderRegistry.register(selector, { + this._registrations.set(handle, modes.ReferenceProviderRegistry.register(selector, { provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Promise => { return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto); } - }); + })); } // --- quick fix $registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void { - this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, { + this._registrations.set(handle, modes.CodeActionProviderRegistry.register(selector, { provideCodeActions: async (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise => { const listDto = await this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token); if (!listDto) { @@ -250,46 +251,46 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha }; }, providedCodeActionKinds - }); + })); } // --- formatting $registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier, displayName: string): void { - this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(selector, { + this._registrations.set(handle, modes.DocumentFormattingEditProviderRegistry.register(selector, { extensionId, displayName, provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise => { return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token); } - }); + })); } $registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier, displayName: string): void { - this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(selector, { + this._registrations.set(handle, modes.DocumentRangeFormattingEditProviderRegistry.register(selector, { extensionId, displayName, provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise => { return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token); } - }); + })); } $registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void { - this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(selector, { + this._registrations.set(handle, modes.OnTypeFormattingEditProviderRegistry.register(selector, { extensionId, autoFormatTriggerCharacters, provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise => { return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token); } - }); + })); } // --- navigate type $registerNavigateTypeSupport(handle: number): void { let lastResultId: number | undefined; - this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register({ + this._registrations.set(handle, search.WorkspaceSymbolProviderRegistry.register({ provideWorkspaceSymbols: (search: string, token: CancellationToken): Promise => { return this._proxy.$provideWorkspaceSymbols(handle, search, token).then(result => { if (lastResultId !== undefined) { @@ -307,21 +308,20 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return undefined; }); } - }); + })); } // --- rename $registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportResolveLocation: boolean): void { - - this._registrations[handle] = modes.RenameProviderRegistry.register(selector, { + this._registrations.set(handle, modes.RenameProviderRegistry.register(selector, { provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Promise => { return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto); }, resolveRenameLocation: supportResolveLocation ? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => this._proxy.$resolveRenameLocation(handle, model.uri, position, token) : undefined - }); + })); } // --- suggest @@ -374,13 +374,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha }); }; } - this._registrations[handle] = modes.CompletionProviderRegistry.register(selector, provider); + this._registrations.set(handle, modes.CompletionProviderRegistry.register(selector, provider)); } // --- parameter hints $registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void { - this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(selector, { + this._registrations.set(handle, modes.SignatureHelpProviderRegistry.register(selector, { signatureHelpTriggerCharacters: metadata.triggerCharacters, signatureHelpRetriggerCharacters: metadata.retriggerCharacters, @@ -397,7 +397,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha } }; } - }); + })); } // --- links @@ -431,14 +431,14 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha }); }; } - this._registrations[handle] = modes.LinkProviderRegistry.register(selector, provider); + this._registrations.set(handle, modes.LinkProviderRegistry.register(selector, provider)); } // --- colors $registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void { const proxy = this._proxy; - this._registrations[handle] = modes.ColorProviderRegistry.register(selector, { + this._registrations.set(handle, modes.ColorProviderRegistry.register(selector, { provideDocumentColors: (model, token) => { return proxy.$provideDocumentColors(handle, model.uri, token) .then(documentColors => { @@ -465,34 +465,34 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha range: colorInfo.range }, token); } - }); + })); } // --- folding $registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void { const proxy = this._proxy; - this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(selector, { + this._registrations.set(handle, modes.FoldingRangeProviderRegistry.register(selector, { provideFoldingRanges: (model, context, token) => { return proxy.$provideFoldingRanges(handle, model.uri, context, token); } - }); + })); } // -- smart select $registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = modes.SelectionRangeRegistry.register(selector, { + this._registrations.set(handle, modes.SelectionRangeRegistry.register(selector, { provideSelectionRanges: (model, positions, token) => { return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token); } - }); + })); } // --- call hierarchy $registerCallHierarchyProvider(handle: number, selector: ISerializedDocumentFilter[]): void { - this._registrations[handle] = callh.CallHierarchyProviderRegistry.register(selector, { + this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, { provideCallHierarchyItem: (document, position, token) => { return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto); }, @@ -510,7 +510,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return data as [callh.CallHierarchyItem, modes.Location[]][]; }); } - }); + })); } // --- configuration @@ -571,7 +571,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha const languageIdentifier = this._modeService.getLanguageIdentifier(languageId); if (languageIdentifier) { - this._registrations[handle] = LanguageConfigurationRegistry.register(languageIdentifier, configuration); + this._registrations.set(handle, LanguageConfigurationRegistry.register(languageIdentifier, configuration)); } } diff --git a/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index b0a25696935..089cb517b45 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -24,7 +24,7 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup { get hideWhenEmpty(): boolean { return !!this.features.hideWhenEmpty; } private _onDidChange = new Emitter(); - get onDidChange(): Event { return this._onDidChange.event; } + readonly onDidChange: Event = this._onDidChange.event; constructor( private readonly sourceControlHandle: number, @@ -105,7 +105,7 @@ class MainThreadSCMProvider implements ISCMProvider { // } private _onDidChangeResources = new Emitter(); - get onDidChangeResources(): Event { return this._onDidChangeResources.event; } + readonly onDidChangeResources: Event = this._onDidChangeResources.event; private features: SCMProviderFeatures = {}; @@ -120,13 +120,13 @@ class MainThreadSCMProvider implements ISCMProvider { get count(): number | undefined { return this.features.count; } private _onDidChangeCommitTemplate = new Emitter(); - get onDidChangeCommitTemplate(): Event { return this._onDidChangeCommitTemplate.event; } + readonly onDidChangeCommitTemplate: Event = this._onDidChangeCommitTemplate.event; private _onDidChangeStatusBarCommands = new Emitter(); get onDidChangeStatusBarCommands(): Event { return this._onDidChangeStatusBarCommands.event; } private _onDidChange = new Emitter(); - get onDidChange(): Event { return this._onDidChange.event; } + readonly onDidChange: Event = this._onDidChange.event; constructor( private readonly proxy: ExtHostSCMShape, diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 7883f70b7b6..f23b625d140 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest } from 'vs/workbench/contrib/terminal/common/terminal'; -import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig } from 'vs/workbench/api/common/extHost.protocol'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; import { StopWatch } from 'vs/base/common/stopwatch'; @@ -18,10 +18,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape private _proxy: ExtHostTerminalServiceShape; private _remoteAuthority: string | null; private readonly _toDispose = new DisposableStore(); - private _terminalProcesses: { [id: number]: Promise } = {}; - private _terminalProcessesReady: { [id: number]: (proxy: ITerminalProcessExtHostProxy) => void } = {}; - private _terminalOnDidWriteDataListeners: { [id: number]: IDisposable } = {}; - private _terminalOnDidAcceptInputListeners: { [id: number]: IDisposable } = {}; + private readonly _terminalProcesses = new Map>(); + private readonly _terminalProcessesReady = new Map void>(); + private readonly _terminalOnDidWriteDataListeners = new Map(); + private readonly _terminalOnDidAcceptInputListeners = new Map(); constructor( extHostContext: IExtHostContext, @@ -35,8 +35,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape // ITerminalService listeners this._toDispose.add(_terminalService.onInstanceCreated((instance) => { // Delay this message so the TerminalInstance constructor has a chance to finish and - // return the ID normally to the extension host. The ID that is passed here will be used - // to register non-extension API terminals in the extension host. + // return the ID normally to the extension host. The ID that is passed here will be + // used to register non-extension API terminals in the extension host. setTimeout(() => { this._onTerminalOpened(instance); this._onInstanceDimensionsChanged(instance); @@ -47,8 +47,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance))); this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance))); - this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request))); - this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(proxy => this._onTerminalRequestVirtualProcess(proxy))); + this._toDispose.add(_terminalService.onInstanceRequestSpawnExtHostProcess(request => this._onRequestSpawnExtHostProcess(request))); + this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e))); this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title))); this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed))); @@ -90,10 +90,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape env: launchConfig.env, strictEnv: launchConfig.strictEnv, hideFromUser: launchConfig.hideFromUser, - isVirtualProcess: launchConfig.isVirtualProcess + isExtensionTerminal: launchConfig.isExtensionTerminal }; const terminal = this._terminalService.createTerminal(shellLaunchConfig); - this._terminalProcesses[terminal.id] = new Promise(r => this._terminalProcessesReady[terminal.id] = r); + this._terminalProcesses.set(terminal.id, new Promise(r => this._terminalProcessesReady.set(terminal.id, r))); return Promise.resolve({ id: terminal.id, name: terminal.title @@ -155,13 +155,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } // Listener already registered - if (this._terminalOnDidAcceptInputListeners.hasOwnProperty(terminalId)) { + if (this._terminalOnDidAcceptInputListeners.has(terminalId)) { return; } // Register - this._terminalOnDidAcceptInputListeners[terminalId] = terminalInstance.onRendererInput(data => this._onTerminalRendererInput(terminalId, data)); - terminalInstance.addDisposable(this._terminalOnDidAcceptInputListeners[terminalId]); + const listener = terminalInstance.onRendererInput(data => this._onTerminalRendererInput(terminalId, data)); + this._terminalOnDidAcceptInputListeners.set(terminalId, listener); + terminalInstance.addDisposable(listener); } public $sendText(terminalId: number, text: string, addNewLine: boolean): void { @@ -178,15 +179,16 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } // Listener already registered - if (this._terminalOnDidWriteDataListeners[terminalId]) { + if (this._terminalOnDidWriteDataListeners.has(terminalId)) { return; } // Register - this._terminalOnDidWriteDataListeners[terminalId] = terminalInstance.onData(data => { + const listener = terminalInstance.onData(data => { this._onTerminalData(terminalId, data); }); - terminalInstance.addDisposable(this._terminalOnDidWriteDataListeners[terminalId]); + this._terminalOnDidWriteDataListeners.set(terminalId, listener); + terminalInstance.addDisposable(listener); } private _onActiveTerminalChanged(terminalId: number | null): void { @@ -238,18 +240,19 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._proxy.$acceptTerminalMaximumDimensions(instance.id, instance.maxCols, instance.maxRows); } - private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void { + private _onRequestSpawnExtHostProcess(request: ISpawnExtHostProcessRequest): void { // Only allow processes on remote ext hosts if (!this._remoteAuthority) { return; } - const ready = this._terminalProcessesReady[request.proxy.terminalId]; + const proxy = request.proxy; + const ready = this._terminalProcessesReady.get(proxy.terminalId); if (ready) { - ready(request.proxy); - delete this._terminalProcessesReady[request.proxy.terminalId]; + ready(proxy); + this._terminalProcessesReady.delete(proxy.terminalId); } else { - this._terminalProcesses[request.proxy.terminalId] = Promise.resolve(request.proxy); + this._terminalProcesses.set(proxy.terminalId, Promise.resolve(proxy)); } const shellLaunchConfigDto: ShellLaunchConfigDto = { name: request.shellLaunchConfig.name, @@ -258,26 +261,32 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape cwd: request.shellLaunchConfig.cwd, env: request.shellLaunchConfig.env }; - this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); - request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data)); - request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows)); - request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate)); - request.proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(request.proxy.terminalId)); - request.proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(request.proxy.terminalId)); - request.proxy.onRequestLatency(() => this._onRequestLatency(request.proxy.terminalId)); + this._proxy.$spawnExtHostProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); + proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data)); + proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows)); + proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); + proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId)); + proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.terminalId)); + proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId)); } - private _onTerminalRequestVirtualProcess(proxy: ITerminalProcessExtHostProxy): void { - const ready = this._terminalProcessesReady[proxy.terminalId]; + private _onRequestStartExtensionTerminal(request: IStartExtensionTerminalRequest): void { + const proxy = request.proxy; + const ready = this._terminalProcessesReady.get(proxy.terminalId); if (!ready) { - this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy); + this._terminalProcesses.set(proxy.terminalId, Promise.resolve(proxy)); } else { ready(proxy); - delete this._terminalProcessesReady[proxy.terminalId]; + this._terminalProcessesReady.delete(proxy.terminalId); } // Note that onReisze is not being listened to here as it needs to fire when max dimensions // change, excluding the dimension override + const initialDimensions: ITerminalDimensionsDto | undefined = request.cols && request.rows ? { + columns: request.cols, + rows: request.rows + } : undefined; + this._proxy.$startExtensionTerminal(proxy.terminalId, initialDimensions); proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId)); @@ -286,32 +295,39 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $sendProcessTitle(terminalId: number, title: string): void { - this._terminalProcesses[terminalId].then(e => e.emitTitle(title)); + this._getTerminalProcess(terminalId).then(e => e.emitTitle(title)); } public $sendProcessData(terminalId: number, data: string): void { - this._terminalProcesses[terminalId].then(e => e.emitData(data)); + this._getTerminalProcess(terminalId).then(e => e.emitData(data)); } public $sendProcessReady(terminalId: number, pid: number, cwd: string): void { - this._terminalProcesses[terminalId].then(e => e.emitReady(pid, cwd)); + this._getTerminalProcess(terminalId).then(e => e.emitReady(pid, cwd)); } public $sendProcessExit(terminalId: number, exitCode: number): void { - this._terminalProcesses[terminalId].then(e => e.emitExit(exitCode)); - delete this._terminalProcesses[terminalId]; + this._getTerminalProcess(terminalId).then(e => e.emitExit(exitCode)); + this._terminalProcesses.delete(terminalId); } public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void { - this._terminalProcesses[terminalId].then(e => e.emitOverrideDimensions(dimensions)); + this._getTerminalProcess(terminalId).then(e => e.emitOverrideDimensions(dimensions)); } public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void { - this._terminalProcesses[terminalId].then(e => e.emitInitialCwd(initialCwd)); + this._getTerminalProcess(terminalId).then(e => e.emitInitialCwd(initialCwd)); } public $sendProcessCwd(terminalId: number, cwd: string): void { - this._terminalProcesses[terminalId].then(e => e.emitCwd(cwd)); + this._getTerminalProcess(terminalId).then(e => e.emitCwd(cwd)); + } + + public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void { + const instance = this._terminalService.getInstanceFromId(terminalId); + if (instance) { + this._getTerminalProcess(terminalId).then(e => e.emitResolvedShellLaunchConfig(shellLaunchConfig)); + } } private async _onRequestLatency(terminalId: number): Promise { @@ -323,7 +339,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape sw.stop(); sum += sw.elapsed(); } - this._terminalProcesses[terminalId].then(e => e.emitLatency(sum / COUNT)); + this._getTerminalProcess(terminalId).then(e => e.emitLatency(sum / COUNT)); } private _isPrimaryExtHost(): boolean { @@ -346,4 +362,12 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._proxy.$requestDefaultShellAndArgs().then(e => request(e.shell, e.args)); } } + + private _getTerminalProcess(terminalId: number): Promise { + const terminal = this._terminalProcesses.get(terminalId); + if (!terminal) { + throw new Error(`Unknown terminal: ${terminalId}`); + } + return terminal; + } } diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index 7a18271ff58..f7024269742 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../common/extHost.protocol'; +import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions } from 'vs/workbench/common/views'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { distinct } from 'vs/base/common/arrays'; diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index e87a48fc9d9..90bdeb5ea74 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,10 @@ 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'; +import { Webview } from 'vs/workbench/contrib/webview/common/webview'; -interface MainThreadWebviewState { +interface OldMainThreadWebviewState { readonly viewType: string; state: any; } @@ -41,9 +42,9 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews private static revivalPool = 0; - private readonly _proxy: ExtHostWebviewsShape; - private readonly _webviews = new Map>(); + private readonly _webviewEditorInputs = new Map(); + private readonly _webviews = new Map(); private readonly _revivers = new Map(); private _activeWebview: WebviewPanelHandle | undefined = undefined; @@ -67,8 +68,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}`); } @@ -93,16 +98,14 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn); } - const webview = this._webviewEditorService.createWebview(this.getInternalWebviewId(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), { + 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); + this._webviewEditorInputs.set(handle, webview); + this._webviews.set(handle, webview.webview); /* __GDPR__ "webviews:createWebviewPanel" : { @@ -113,17 +116,17 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } public $disposeWebview(handle: WebviewPanelHandle): void { - const webview = this.getWebview(handle); + const webview = this.getWebviewEditorInput(handle); webview.dispose(); } public $setTitle(handle: WebviewPanelHandle, value: string): void { - const webview = this.getWebview(handle); + const webview = this.getWebviewEditorInput(handle); webview.setName(value); } public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void { - const webview = this.getWebview(handle); + const webview = this.getWebviewEditorInput(handle); webview.iconPath = reviveWebviewIcon(value); } @@ -134,11 +137,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void { const webview = this.getWebview(handle); - webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */)); + webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */); } public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void { - const webview = this.getWebview(handle); + const webview = this.getWebviewEditorInput(handle); if (webview.isDisposed()) { return; } @@ -151,22 +154,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.sendMessage(message); + return true; } public $registerSerializer(viewType: string): void { @@ -175,28 +164,44 @@ 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._webviewEditorInputs.set(handle, webviewEditorInput); + this._webviews.set(handle, webviewEditorInput.webview); + 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); } } })); @@ -212,35 +217,41 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews this._revivers.delete(viewType); } - private getInternalWebviewId(viewType: string): string { + private getInternalWebviewViewType(viewType: string): string { 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._webviewEditorInputs.delete(handle); + this._webviews.delete(handle); + }); + }); + input.webview.onDidUpdateState((newState: any) => { + const webview = this.tryGetWebviewEditorInput(handle); + if (!webview || webview.isDisposed()) { + return; } - }; + webview.webview.state = newState; + }); } private onActiveEditorChanged() { const activeEditor = this._editorService.activeControl; let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined; if (activeEditor && activeEditor.input instanceof WebviewEditorInput) { - for (const handle of map.keys(this._webviews)) { - const input = this._webviews.get(handle)!; + for (const handle of map.keys(this._webviewEditorInputs)) { + const input = this._webviewEditorInputs.get(handle)!; if (input.matches(activeEditor.input)) { newActiveWebview = { input, handle }; break; @@ -260,7 +271,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews // Broadcast view state update for currently active if (typeof this._activeWebview !== 'undefined') { - const oldActiveWebview = this._webviews.get(this._activeWebview); + const oldActiveWebview = this._webviewEditorInputs.get(this._activeWebview); if (oldActiveWebview) { this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, { active: false, @@ -284,7 +295,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } private onVisibleEditorsChanged(): void { - this._webviews.forEach((input, handle) => { + this._webviewEditorInputs.forEach((input, handle) => { for (const workbenchEditor of this._editorService.visibleControls) { if (workbenchEditor.input && workbenchEditor.input.matches(input)) { const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group!); @@ -306,7 +317,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews return; } - const webview = this.getWebview(handle); + const webview = this.getWebviewEditorInput(handle); if (this.isSupportedLink(webview, link)) { this._openerService.open(link); } @@ -319,10 +330,22 @@ 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 { + private getWebviewEditorInput(handle: WebviewPanelHandle): WebviewEditorInput { + const webview = this.tryGetWebviewEditorInput(handle); + if (!webview) { + throw new Error('Unknown webview handle:' + handle); + } + return webview; + } + + private tryGetWebviewEditorInput(handle: WebviewPanelHandle): WebviewEditorInput | undefined { + return this._webviewEditorInputs.get(handle); + } + + private getWebview(handle: WebviewPanelHandle): Webview { const webview = this.tryGetWebview(handle); if (!webview) { throw new Error('Unknown webview handle:' + handle); @@ -330,7 +353,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews return webview; } - private tryGetWebview(handle: WebviewPanelHandle): WebviewEditorInput | undefined { + private tryGetWebview(handle: WebviewPanelHandle): Webview | undefined { return this._webviews.get(handle); } @@ -347,13 +370,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/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index f8cb326f992..f0c9c62ec00 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -24,6 +24,7 @@ import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, Ma import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isEqualOrParent } from 'vs/base/common/resources'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { withNullAsUndefined } from 'vs/base/common/types'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -122,21 +123,21 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- search --- - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false | undefined, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string | null, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise { const includeFolder = URI.revive(_includeFolder); const workspace = this._contextService.getWorkspace(); if (!workspace.folders.length) { - return Promise.resolve(undefined); + return Promise.resolve(null); } const query = this._queryBuilder.file( includeFolder ? [includeFolder] : workspace.folders.map(f => f.uri), { - maxResults, + maxResults: withNullAsUndefined(maxResults), disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined, disregardSearchExcludeSettings: true, disregardIgnoreFiles: true, - includePattern, + includePattern: withNullAsUndefined(includePattern), excludePattern: typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined, _reason: 'startFileSearch' }); @@ -179,10 +180,9 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return search; } - $checkExists(includes: string[], token: CancellationToken): Promise { + $checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise { const queryBuilder = this._instantiationService.createInstance(QueryBuilder); - const folders = this._contextService.getWorkspace().folders.map(folder => folder.uri); - const query = queryBuilder.file(folders, { + const query = queryBuilder.file(folders.map(folder => URI.revive(folder)), { _reason: 'checkExists', includePattern: includes.join(', '), expandPatterns: true, diff --git a/src/vs/workbench/api/common/apiCommands.ts b/src/vs/workbench/api/common/apiCommands.ts index 0c303c05c44..0c5b098cd6a 100644 --- a/src/vs/workbench/api/common/apiCommands.ts +++ b/src/vs/workbench/api/common/apiCommands.ts @@ -12,7 +12,6 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenSettings, IURIToOpen, IWindowService } from 'vs/platform/windows/common/windows'; -import { IDownloadService } from 'vs/platform/download/common/download'; import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { IRecent } from 'vs/platform/history/common/history'; import { Schemas } from 'vs/base/common/network'; @@ -206,9 +205,4 @@ CommandsRegistry.registerCommand({ } }] } -}); - -CommandsRegistry.registerCommand('_workbench.downloadResource', function (accessor: ServicesAccessor, resource: URI) { - const downloadService = accessor.get(IDownloadService); - return downloadService.download(resource).then(location => URI.file(location)); -}); +}); \ No newline at end of file diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index e28c6f484ba..e224dcc9c5d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -21,7 +21,7 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model' import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel'; import * as modes from 'vs/editor/common/modes'; import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration'; -import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; +import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; @@ -31,7 +31,7 @@ import { LogLevel } from 'vs/platform/log/common/log'; import { IMarkerData } from 'vs/platform/markers/common/markers'; import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress'; import * as quickInput from 'vs/platform/quickinput/common/quickInput'; -import { RemoteAuthorityResolverErrorCode, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import * as statusbar from 'vs/platform/statusbar/common/statusbar'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; @@ -40,9 +40,9 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import * as tasks from 'vs/workbench/api/common/shared/tasks'; import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views'; import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; -import { IAdapterDescriptor, IConfig, ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; +import { IAdapterDescriptor, IConfig } from 'vs/workbench/contrib/debug/common/debug'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; -import { ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import * as search from 'vs/workbench/services/search/common/search'; @@ -115,6 +115,8 @@ export interface MainThreadClipboardShape extends IDisposable { export interface MainThreadCommandsShape extends IDisposable { $registerCommand(id: string): void; + $registerCommandListener(): void; + $unregisterCommandListener(): void; $unregisterCommand(id: string): void; $executeCommand(id: string, args: any[]): Promise; $getCommands(): Promise; @@ -246,6 +248,10 @@ export interface MainThreadTreeViewsShape extends IDisposable { $setMessage(treeViewId: string, message: string | IMarkdownString): void; } +export interface MainThreadDownloadServiceShape extends IDisposable { + $download(uri: UriComponents, to: UriComponents): Promise; +} + export interface MainThreadErrorsShape extends IDisposable { $onUnexpectedError(err: any | SerializedError): void; } @@ -384,7 +390,7 @@ export interface TerminalLaunchConfig { waitOnExit?: boolean; strictEnv?: boolean; hideFromUser?: boolean; - isVirtualProcess?: boolean; + isExtensionTerminal?: boolean; } export interface MainThreadTerminalServiceShape extends IDisposable { @@ -401,9 +407,10 @@ export interface MainThreadTerminalServiceShape extends IDisposable { $sendProcessData(terminalId: number, data: string): void; $sendProcessReady(terminalId: number, pid: number, cwd: string): void; $sendProcessExit(terminalId: number, exitCode: number): void; - $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void; $sendProcessInitialCwd(terminalId: number, cwd: string): void; $sendProcessCwd(terminalId: number, initialCwd: string): void; + $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void; + $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void; // Renderer $terminalRendererSetName(terminalId: number, name: string): void; @@ -575,9 +582,9 @@ export interface ITextSearchComplete { } export interface MainThreadWorkspaceShape extends IDisposable { - $startFileSearch(includePattern: string | undefined, includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false | undefined, maxResults: number | undefined, token: CancellationToken): Promise; + $startFileSearch(includePattern: string | null, includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise; $startTextSearch(query: search.IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise; - $checkExists(includes: string[], token: CancellationToken): Promise; + $checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise; $saveAll(includeUntitled?: boolean): Promise; $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Promise; $resolveProxy(url: string): Promise; @@ -732,6 +739,7 @@ export interface MainThreadWindowShape extends IDisposable { export interface ExtHostCommandsShape { $executeContributedCommand(id: string, ...args: any[]): Promise; $getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }>; + $handleDidExecuteCommand(command: ICommandEvent): void; } export interface ExtHostConfigurationShape { @@ -811,6 +819,9 @@ export interface ExtHostTreeViewsShape { $setVisible(treeViewId: string, visible: boolean): void; } +export interface ExtHostDownloadServiceShape { +} + export interface ExtHostWorkspaceShape { $initializeWorkspace(workspace: IWorkspaceData | null): void; $acceptWorkspaceData(workspace: IWorkspaceData | null): void; @@ -855,7 +866,7 @@ export interface IResolveAuthorityErrorResult { export interface IResolveAuthorityOKResult { type: 'ok'; - value: ResolvedAuthority; + value: ResolverResult; } export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAuthorityOKResult; @@ -1135,6 +1146,11 @@ export interface IShellAndArgsDto { args: string[] | string | undefined; } +export interface ITerminalDimensionsDto { + columns: number; + rows: number; +} + export interface ExtHostTerminalServiceShape { $acceptTerminalClosed(id: number): void; $acceptTerminalOpened(id: number, name: string): void; @@ -1145,7 +1161,8 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalTitleChange(id: number, name: string): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; - $createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + $spawnExtHostProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; $acceptProcessInput(id: number, data: string): void; $acceptProcessResize(id: number, cols: number, rows: number): void; $acceptProcessShutdown(id: number, immediate: boolean): void; @@ -1228,7 +1245,7 @@ export type IDebugSessionDto = IDebugSessionFullDto | DebugSessionUUID; export interface ExtHostDebugServiceShape { $substituteVariables(folder: UriComponents | undefined, config: IConfig): Promise; - $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; + $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise; $startDASession(handle: number, session: IDebugSessionDto): Promise; $stopDASession(handle: number): Promise; $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void; @@ -1278,7 +1295,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; } @@ -1304,6 +1320,7 @@ export const MainContext = { MainThreadEditorInsets: createMainId('MainThreadEditorInsets'), MainThreadErrors: createMainId('MainThreadErrors'), MainThreadTreeViews: createMainId('MainThreadTreeViews'), + MainThreadDownloadService: createMainId('MainThreadDownloadService'), MainThreadKeytar: createMainId('MainThreadKeytar'), MainThreadLanguageFeatures: createMainId('MainThreadLanguageFeatures'), MainThreadLanguages: createMainId('MainThreadLanguages'), @@ -1339,6 +1356,7 @@ export const ExtHostContext = { ExtHostDocumentSaveParticipant: createExtId('ExtHostDocumentSaveParticipant'), ExtHostEditors: createExtId('ExtHostEditors'), ExtHostTreeViews: createExtId('ExtHostTreeViews'), + ExtHostDownloadService: createExtId('ExtHostDownloadService'), ExtHostFileSystem: createExtId('ExtHostFileSystem'), ExtHostFileSystemEventService: createExtId('ExtHostFileSystemEventService'), ExtHostLanguageFeatures: createExtId('ExtHostLanguageFeatures'), diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index 3d0840068b0..19e4d5655f1 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { validateConstraint } from 'vs/base/common/types'; -import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; +import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters'; import { cloneAndChange } from 'vs/base/common/objects'; @@ -17,6 +17,7 @@ import { revive } from 'vs/base/common/marshalling'; import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { URI } from 'vs/base/common/uri'; +import { Event, Emitter } from 'vs/base/common/event'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; interface CommandHandler { @@ -31,6 +32,9 @@ export interface ArgumentProcessor { export class ExtHostCommands implements ExtHostCommandsShape { + private readonly _onDidExecuteCommand: Emitter; + readonly onDidExecuteCommand: Event; + private readonly _commands = new Map(); private readonly _proxy: MainThreadCommandsShape; private readonly _converter: CommandsConverter; @@ -42,6 +46,11 @@ export class ExtHostCommands implements ExtHostCommandsShape { logService: ILogService ) { this._proxy = mainContext.getProxy(MainContext.MainThreadCommands); + this._onDidExecuteCommand = new Emitter({ + onFirstListenerDidAdd: () => this._proxy.$registerCommandListener(), + onLastListenerRemove: () => this._proxy.$unregisterCommandListener(), + }); + this.onDidExecuteCommand = Event.filter(this._onDidExecuteCommand.event, e => e.command[0] !== '_'); // filter 'private' commands this._logService = logService; this._converter = new CommandsConverter(this); this._argumentProcessors = [ @@ -106,6 +115,13 @@ export class ExtHostCommands implements ExtHostCommandsShape { }); } + $handleDidExecuteCommand(command: ICommandEvent): void { + this._onDidExecuteCommand.fire({ + command: command.commandId, + arguments: command.args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r), arg)) + }); + } + executeCommand(id: string, ...args: any[]): Promise { this._logService.trace('ExtHostCommands#executeCommand', id); @@ -154,6 +170,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { try { const result = callback.apply(thisArg, args); + this._onDidExecuteCommand.fire({ command: id, arguments: args }); return Promise.resolve(result); } catch (err) { this._logService.error(err, id); @@ -205,7 +222,7 @@ export class CommandsConverter { // --- conversion between internal and api commands constructor(commands: ExtHostCommands) { - this._delegatingCommandId = `_internal_command_delegation_${Date.now()}`; + this._delegatingCommandId = `_vscode_delegate_cmd_${Date.now().toString(36)}`; this._commands = commands; this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this); } diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index 10166047fb2..b71643ba369 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/common/extHostFileSystem.ts b/src/vs/workbench/api/common/extHostFileSystem.ts index c73831e687e..9f0519b636f 100644 --- a/src/vs/workbench/api/common/extHostFileSystem.ts +++ b/src/vs/workbench/api/common/extHostFileSystem.ts @@ -192,23 +192,23 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { this._usedSchemes.add(scheme); this._fsProvider.set(handle, provider); - let capabilites = files.FileSystemProviderCapabilities.FileReadWrite; + let capabilities = files.FileSystemProviderCapabilities.FileReadWrite; if (options.isCaseSensitive) { - capabilites += files.FileSystemProviderCapabilities.PathCaseSensitive; + capabilities += files.FileSystemProviderCapabilities.PathCaseSensitive; } if (options.isReadonly) { - capabilites += files.FileSystemProviderCapabilities.Readonly; + capabilities += files.FileSystemProviderCapabilities.Readonly; } if (typeof provider.copy === 'function') { - capabilites += files.FileSystemProviderCapabilities.FileFolderCopy; + capabilities += files.FileSystemProviderCapabilities.FileFolderCopy; } if (typeof provider.open === 'function' && typeof provider.close === 'function' && typeof provider.read === 'function' && typeof provider.write === 'function' ) { - capabilites += files.FileSystemProviderCapabilities.FileOpenReadWriteClose; + capabilities += files.FileSystemProviderCapabilities.FileOpenReadWriteClose; } - this._proxy.$registerFileSystemProvider(handle, scheme, capabilites); + this._proxy.$registerFileSystemProvider(handle, scheme, capabilities); const subscription = provider.onDidChangeFile(event => { const mapped: IFileChangeDto[] = []; diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 675201e622f..311981d6f4d 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -6,7 +6,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { debounce } from 'vs/base/common/decorators'; -import { dispose, IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { asPromise } from 'vs/base/common/async'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, CommandDto } from './extHost.protocol'; @@ -263,7 +263,6 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG } readonly handle = ExtHostSourceControlResourceGroup._handlePool++; - private _disposables: IDisposable[] = []; constructor( private _proxy: MainThreadSCMShape, @@ -353,7 +352,6 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG dispose(): void { this._proxy.$unregisterGroup(this._sourceControlHandle, this.handle); - this._disposables = dispose(this._disposables); this._onDidDispose.fire(); } } diff --git a/src/vs/workbench/api/common/extHostTextEditor.ts b/src/vs/workbench/api/common/extHostTextEditor.ts index f97da57cf53..fa10d30014b 100644 --- a/src/vs/workbench/api/common/extHostTextEditor.ts +++ b/src/vs/workbench/api/common/extHostTextEditor.ts @@ -51,21 +51,21 @@ export class TextEditorEdit { private readonly _document: vscode.TextDocument; private readonly _documentVersionId: number; - private _collectedEdits: ITextEditOperation[]; - private _setEndOfLine: EndOfLine | undefined; private readonly _undoStopBefore: boolean; private readonly _undoStopAfter: boolean; + private _collectedEdits: ITextEditOperation[] = []; + private _setEndOfLine: EndOfLine | undefined = undefined; + private _finalized: boolean = false; constructor(document: vscode.TextDocument, options: { undoStopBefore: boolean; undoStopAfter: boolean; }) { this._document = document; this._documentVersionId = document.version; - this._collectedEdits = []; - this._setEndOfLine = undefined; this._undoStopBefore = options.undoStopBefore; this._undoStopAfter = options.undoStopAfter; } finalize(): IEditData { + this._finalized = true; return { documentVersionId: this._documentVersionId, edits: this._collectedEdits, @@ -75,7 +75,14 @@ export class TextEditorEdit { }; } + private _throwIfFinalized() { + if (this._finalized) { + throw new Error('Edit is only valid while callback runs'); + } + } + replace(location: Position | Range | Selection, value: string): void { + this._throwIfFinalized(); let range: Range | null = null; if (location instanceof Position) { @@ -90,10 +97,12 @@ export class TextEditorEdit { } insert(location: Position, value: string): void { + this._throwIfFinalized(); this._pushEdit(new Range(location, location), value, true); } delete(location: Range | Selection): void { + this._throwIfFinalized(); let range: Range | null = null; if (location instanceof Range) { @@ -115,6 +124,7 @@ export class TextEditorEdit { } setEndOfLine(endOfLine: EndOfLine): void { + this._throwIfFinalized(); if (endOfLine !== EndOfLine.LF && endOfLine !== EndOfLine.CRLF) { throw illegalArgument('endOfLine'); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index df40f2256ff..39b2cda9188 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -108,6 +108,8 @@ export namespace DiagnosticTag { switch (value) { case types.DiagnosticTag.Unnecessary: return MarkerTag.Unnecessary; + case types.DiagnosticTag.Deprecated: + return MarkerTag.Deprecated; } return undefined; } @@ -237,8 +239,7 @@ export namespace MarkdownString { const resUris: { [href: string]: UriComponents } = Object.create(null); res.uris = resUris; - const renderer = new marked.Renderer(); - renderer.image = renderer.link = (href: string): string => { + const collectUri = (href: string): string => { try { let uri = URI.parse(href, true); uri = uri.with({ query: _uriMassage(uri.query, resUris) }); @@ -248,6 +249,10 @@ export namespace MarkdownString { } return ''; }; + const renderer = new marked.Renderer(); + renderer.link = collectUri; + renderer.image = href => collectUri(htmlContent.parseHrefAndDimensions(href).href); + marked(res.value, { renderer }); return res; @@ -985,8 +990,9 @@ export namespace GlobPattern { export function from(pattern: vscode.GlobPattern): string | types.RelativePattern; export function from(pattern: undefined): undefined; - export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined; - export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined { + export function from(pattern: null): null; + export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null; + export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null { if (pattern instanceof types.RelativePattern) { return pattern; } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index b8aebf92b45..0a0ce14f00e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -773,6 +773,7 @@ export class SnippetString { export enum DiagnosticTag { Unnecessary = 1, + Deprecated = 2 } export enum DiagnosticSeverity { @@ -1773,19 +1774,19 @@ export class CustomExecution implements vscode.CustomExecution { } export class CustomExecution2 implements vscode.CustomExecution2 { - private _callback: () => Thenable; - constructor(callback: () => Thenable) { + private _callback: () => Thenable; + constructor(callback: () => Thenable) { this._callback = callback; } public computeId(): string { return 'customExecution' + generateUuid(); } - public set callback(value: () => Thenable) { + public set callback(value: () => Thenable) { this._callback = value; } - public get callback(): (() => Thenable) { + public get callback(): (() => Thenable) { return this._callback; } } diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index cc83d789340..aaa6a49734c 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -40,7 +40,7 @@ export class ExtHostWebview implements vscode.Webview { } public get cspSource(): string { - return this._initData.webviewCspSource; + return this._initData.webviewCspSource.replace('{{uuid}}', this._handle); } public get html(): string { diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index bf8abf0eab9..a97d82b4935 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -9,7 +9,6 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; import { TernarySearchTree } from 'vs/base/common/map'; import { Counter } from 'vs/base/common/numbers'; -import { isLinux } from 'vs/base/common/platform'; import { basenameOrAuthority, dirname, isEqual, relativePath, basename } from 'vs/base/common/resources'; import { compare } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; @@ -25,6 +24,7 @@ import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, M import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Barrier } from 'vs/base/common/async'; import { Schemas } from 'vs/base/common/network'; +import { withUndefinedAsNull } from 'vs/base/common/types'; export interface IExtHostWorkspaceProvider { getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise; @@ -34,7 +34,7 @@ export interface IExtHostWorkspaceProvider { } function isFolderEqual(folderA: URI, folderB: URI): boolean { - return isEqual(folderA, folderB, !isLinux); + return isEqual(folderA, folderB); } function compareWorkspaceFolderByUri(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number { @@ -408,7 +408,10 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac // --- search --- - findFiles(include: string | RelativePattern | undefined, exclude: vscode.GlobPattern | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { + /** + * Note, null/undefined have different and important meanings for "exclude" + */ + findFiles(include: string | RelativePattern | undefined, exclude: vscode.GlobPattern | null | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`); let includePattern: string | undefined; @@ -439,7 +442,13 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac return Promise.resolve([]); } - return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token) + return this._proxy.$startFileSearch( + withUndefinedAsNull(includePattern), + withUndefinedAsNull(includeFolder), + withUndefinedAsNull(excludePatternOrDisregardExcludes), + withUndefinedAsNull(maxResults), + token + ) .then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : []); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 6b05ef0759e..f4df88c11ba 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -49,6 +49,7 @@ import { ExtHostTask } from 'vs/workbench/api/node/extHostTask'; import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService'; import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors'; import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews'; +import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls'; @@ -62,12 +63,15 @@ import * as vscode from 'vscode'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { originalFSPath } from 'vs/base/common/resources'; import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer'; -import { withNullAsUndefined } from 'vs/base/common/types'; import { values } from 'vs/base/common/collections'; import { Schemas } from 'vs/base/common/network'; import { IURITransformer } from 'vs/base/common/uriIpc'; import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets'; import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; +import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; +import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -95,6 +99,10 @@ export function createApiFactory( uriTransformer: IURITransformer | null ): IExtensionApiFactory { + // bootstrap services + const services = new ServiceCollection(...getSingletonServiceDescriptors()); + const instaService = new InstantiationService(services); + // Addressable instances rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService); const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(rpcProtocol)); @@ -107,6 +115,7 @@ export function createApiFactory( const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors)); const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostLogService)); const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService)); + rpcProtocol.set(ExtHostContext.ExtHostDownloadService, new ExtHostDownloadService(rpcProtocol.getProxy(MainContext.MainThreadDownloadService), extHostCommands)); rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace); rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment)); @@ -116,7 +125,7 @@ export function createApiFactory( const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors)); const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands)); const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostWorkspace, extHostDocumentsAndEditors, extHostLogService)); - const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands)); + const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, instaService.createInstance(ExtHostDebugService, rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands)); const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService)); const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments)); const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, uriTransformer, extHostLogService)); @@ -235,7 +244,11 @@ export function createApiFactory( }, getCommands(filterInternal: boolean = false): Thenable { return extHostCommands.getCommands(filterInternal); - } + }, + onDidExecuteCommand: proposedApiFunction(extension, (listener, thisArgs?, disposables?) => { + checkProposedApiEnabled(extension); + return extHostCommands.onDidExecuteCommand(listener, thisArgs, disposables); + }), }; // namespace: env @@ -264,15 +277,7 @@ export function createApiFactory( return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, get remoteName() { - if (!initData.remote.authority) { - return undefined; - } - const pos = initData.remote.authority.indexOf('+'); - if (pos < 0) { - // funky? bad authority? - return initData.remote.authority; - } - return initData.remote.authority.substr(0, pos); + return getRemoteName(initData.remote.authority); } }; if (!initData.environment.extensionTestsLocationURI) { @@ -523,10 +528,10 @@ export function createApiFactory( checkProposedApiEnabled(extension); return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension); }, - createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.TerminalVirtualProcessOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { + createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { if (typeof nameOrOptions === 'object') { - if ('virtualProcess' in nameOrOptions) { - return extHostTerminalService.createVirtualProcessTerminal(nameOrOptions); + if ('pty' in nameOrOptions) { + return extHostTerminalService.createExtensionTerminal(nameOrOptions); } else { nameOrOptions.hideFromUser = nameOrOptions.hideFromUser || (nameOrOptions.runInBackground && extension.enableProposedApi); return extHostTerminalService.createTerminalFromOptions(nameOrOptions); @@ -596,7 +601,8 @@ export function createApiFactory( return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace); }, findFiles: (include, exclude, maxResults?, token?) => { - return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(withNullAsUndefined(exclude)), maxResults, extension.identifier, token); + // Note, undefined/null have different meanings on "exclude" + return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token); }, findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback: vscode.FindTextInFilesOptions | ((result: vscode.TextSearchResult) => void), callbackOrToken?: vscode.CancellationToken | ((result: vscode.TextSearchResult) => void), token?: vscode.CancellationToken) => { let options: vscode.FindTextInFilesOptions; diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts index 2c549734a17..3b06ea4c064 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/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 7683b5e9478..be353ca5bde 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -20,7 +20,7 @@ import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstract import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; @@ -34,6 +34,8 @@ import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { SignService } from 'vs/platform/sign/node/signService'; +import { ISignService } from 'vs/platform/sign/common/sign'; export class ExtHostDebugService implements ExtHostDebugServiceShape { @@ -81,6 +83,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { private _integratedTerminalInstance?: vscode.Terminal; private _terminalDisposedListener: IDisposable; + private _signService: ISignService; + constructor(mainContext: IMainContext, private _workspaceService: IExtHostWorkspaceProvider, @@ -314,7 +318,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { // RPC methods (ExtHostDebugServiceShape) - public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { + public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { if (args.kind === 'integrated') { @@ -337,10 +341,22 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } else { resolve(true); } - }).then(needNewTerminal => { + }).then(async needNewTerminal => { + + const configProvider = await this._configurationService.getConfigProvider(); + const shell = this._terminalService.getDefaultShell(configProvider); if (needNewTerminal || !this._integratedTerminalInstance) { - this._integratedTerminalInstance = this._terminalService.createTerminal(args.title || nls.localize('debug.terminal.title', "debuggee")); + const options: vscode.TerminalOptions = { + shellPath: shell, + // shellArgs: this._terminalService._getDefaultShellArgs(configProvider), + cwd: args.cwd, + name: args.title || nls.localize('debug.terminal.title', "debuggee"), + env: args.env + }; + delete args.cwd; + delete args.env; + this._integratedTerminalInstance = this._terminalService.createTerminalFromOptions(options); } const terminal: vscode.Terminal = this._integratedTerminalInstance; @@ -348,7 +364,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return this._integratedTerminalInstance.processId.then(shellProcessId => { - const command = prepareCommand(args, config); + const command = prepareCommand(args, shell, configProvider); + terminal.sendText(command, true); return shellProcessId; @@ -357,7 +374,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } else if (args.kind === 'external') { - runInExternalTerminal(args, config); + runInExternalTerminal(args, await this._configurationService.getConfigProvider()); } return Promise.resolve(undefined); } @@ -421,16 +438,45 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { this._debugAdaptersTrackers.set(debugAdapterHandle, tracker); } - debugAdapter.onMessage(message => { + debugAdapter.onMessage(async message => { - if (tracker && tracker.onDidSendMessage) { - tracker.onDidSendMessage(message); + if (message.type === 'request' && (message).command === 'handshake') { + + const request = message; + + const response: DebugProtocol.Response = { + type: 'response', + seq: 0, + command: request.command, + request_seq: request.seq, + success: true + }; + + if (!this._signService) { + this._signService = new SignService(); + } + + try { + const signature = await this._signService.sign(request.arguments.value); + response.body = { + signature: signature + }; + debugAdapter.sendResponse(response); + } catch (e) { + response.success = false; + response.message = e.message; + debugAdapter.sendResponse(response); + } + } else { + if (tracker && tracker.onDidSendMessage) { + tracker.onDidSendMessage(message); + } + + // DA -> VS Code + message = convertToVSCPaths(message, true); + + mythis._debugServiceProxy.$acceptDAMessage(debugAdapterHandle, message); } - - // DA -> VS Code - message = convertToVSCPaths(message, true); - - mythis._debugServiceProxy.$acceptDAMessage(debugAdapterHandle, message); }); debugAdapter.onError(err => { if (tracker && tracker.onError) { diff --git a/src/vs/workbench/api/node/extHostDownloadService.ts b/src/vs/workbench/api/node/extHostDownloadService.ts new file mode 100644 index 00000000000..c86a8ecd8f9 --- /dev/null +++ b/src/vs/workbench/api/node/extHostDownloadService.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { join } from 'vs/base/common/path'; +import { tmpdir } from 'os'; +import { generateUuid } from 'vs/base/common/uuid'; +import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { MainThreadDownloadServiceShape } from 'vs/workbench/api/common/extHost.protocol'; +import { URI } from 'vs/base/common/uri'; + +export class ExtHostDownloadService extends Disposable { + + constructor( + proxy: MainThreadDownloadServiceShape, + commands: ExtHostCommands + ) { + super(); + commands.registerCommand(false, '_workbench.downloadResource', async (resource: URI): Promise => { + const location = URI.file(join(tmpdir(), generateUuid())); + await proxy.$download(resource, location); + return location; + }); + } + +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index f6bf6877dfd..18e6bf78416 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import { originalFSPath } from 'vs/base/common/resources'; import { Barrier } from 'vs/base/common/async'; -import { dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; @@ -26,7 +26,6 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import * as vscode from 'vscode'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { IWorkspace } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; import { withNullAsUndefined } from 'vs/base/common/types'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -34,6 +33,7 @@ import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento'; import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths'; import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes'; import { IURITransformer } from 'vs/base/common/uriIpc'; +import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver'; interface ITestRunner { /** Old test runner API, as exported from `vscode/lib/testrunner` */ @@ -91,6 +91,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private _started: boolean; + private readonly _disposables: DisposableStore; + constructor( hostUtils: IHostUtils, initData: IInitData, @@ -108,6 +110,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { this._extHostConfiguration = extHostConfiguration; this._environment = environment; this._extHostLogService = extHostLogService; + this._disposables = new DisposableStore(); this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace); this._mainThreadTelemetryProxy = this._extHostContext.getProxy(MainContext.MainThreadTelemetry); @@ -314,15 +317,6 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private _logExtensionActivationTimes(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason, outcome: string, activationTimes?: ExtensionActivationTimes) { const event = getTelemetryActivationEvent(extensionDescription, reason); - /* __GDPR__ - "extensionActivationTimes" : { - "${include}": [ - "${TelemetryActivationEvent}", - "${ExtensionActivationTimes}" - ], - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ type ExtensionActivationTimesClassification = { outcome: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; } & TelemetryActivationEventFragment & ExtensionActivationTimesFragment; @@ -433,27 +427,33 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { console.error(err); }); - return this._handleWorkspaceContainsEagerExtensions(this._extHostWorkspace.workspace); + this._disposables.add(this._extHostWorkspace.onDidChangeWorkspace((e) => this._handleWorkspaceContainsEagerExtensions(e.added))); + const folders = this._extHostWorkspace.workspace ? this._extHostWorkspace.workspace.folders : []; + return this._handleWorkspaceContainsEagerExtensions(folders); } - private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspace | undefined): Promise { - if (!workspace || workspace.folders.length === 0) { + private _handleWorkspaceContainsEagerExtensions(folders: ReadonlyArray): Promise { + if (folders.length === 0) { return Promise.resolve(undefined); } return Promise.all( this._registry.getAllExtensionDescriptions().map((desc) => { - return this._handleWorkspaceContainsEagerExtension(workspace, desc); + return this._handleWorkspaceContainsEagerExtension(folders, desc); }) ).then(() => { }); } - private _handleWorkspaceContainsEagerExtension(workspace: IWorkspace, desc: IExtensionDescription): Promise { + private _handleWorkspaceContainsEagerExtension(folders: ReadonlyArray, desc: IExtensionDescription): Promise { const activationEvents = desc.activationEvents; if (!activationEvents) { return Promise.resolve(undefined); } + if (this.isActivated(desc.identifier)) { + return Promise.resolve(undefined); + } + const fileNames: string[] = []; const globPatterns: string[] = []; @@ -472,16 +472,16 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { return Promise.resolve(undefined); } - const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(workspace, desc.identifier, fileName))).then(() => { }); - const globPatternPromise = this._activateIfGlobPatterns(desc.identifier, globPatterns); + const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(folders, desc.identifier, fileName))).then(() => { }); + const globPatternPromise = this._activateIfGlobPatterns(folders, desc.identifier, globPatterns); return Promise.all([fileNamePromise, globPatternPromise]).then(() => { }); } - private async _activateIfFileName(workspace: IWorkspace, extensionId: ExtensionIdentifier, fileName: string): Promise { + private async _activateIfFileName(folders: ReadonlyArray, extensionId: ExtensionIdentifier, fileName: string): Promise { // find exact path - for (const { uri } of workspace.folders) { + for (const { uri } of folders) { if (await this._hostUtils.exists(path.join(URI.revive(uri).fsPath, fileName))) { // the file was found return ( @@ -494,7 +494,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { return undefined; } - private async _activateIfGlobPatterns(extensionId: ExtensionIdentifier, globPatterns: string[]): Promise { + private async _activateIfGlobPatterns(folders: ReadonlyArray, extensionId: ExtensionIdentifier, globPatterns: string[]): Promise { this._extHostLogService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId.value}, entryPoint: workspaceContains`); if (globPatterns.length === 0) { @@ -502,7 +502,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { } const tokenSource = new CancellationTokenSource(); - const searchP = this._mainThreadWorkspaceProxy.$checkExists(globPatterns, tokenSource.token); + const searchP = this._mainThreadWorkspaceProxy.$checkExists(folders.map(folder => folder.uri), globPatterns, tokenSource.token); const timer = setTimeout(async () => { tokenSource.cancel(); @@ -654,12 +654,22 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { try { const result = await resolver.resolve(remoteAuthority, { resolveAttempt }); + + // Split merged API result into separate authority/options + const authority: ResolvedAuthority = { + authority: remoteAuthority, + host: result.host, + port: result.port + }; + const options: ResolvedOptions = { + extensionHostEnv: result.extensionHostEnv + }; + return { type: 'ok', value: { - authority: remoteAuthority, - host: result.host, - port: result.port, + authority, + options } }; } catch (err) { diff --git a/src/vs/workbench/api/node/extHostRequireInterceptor.ts b/src/vs/workbench/api/node/extHostRequireInterceptor.ts index c73c005de92..789ece36253 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/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index a682a2a4575..9191b53aa47 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -31,7 +31,7 @@ import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfigurati import { ExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/node/extHostTerminalService'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; namespace TaskDefinitionDTO { @@ -377,7 +377,7 @@ class CustomExecutionData implements IDisposable { private static waitForDimensionsTimeoutInMs: number = 5000; private _cancellationSource?: CancellationTokenSource; private readonly _onTaskExecutionComplete: Emitter = new Emitter(); - private readonly _disposables: IDisposable[] = []; + private readonly _disposables = new DisposableStore(); private terminal?: vscode.Terminal; private terminalId?: number; public result: number | undefined; @@ -389,7 +389,7 @@ class CustomExecutionData implements IDisposable { public dispose(): void { this._cancellationSource = undefined; - dispose(this._disposables); + this._disposables.dispose(); } public get onTaskExecutionComplete(): Event { @@ -426,7 +426,7 @@ class CustomExecutionData implements IDisposable { const callbackTerminals: vscode.Terminal[] = this.terminalService.terminals.filter((terminal) => terminal._id === terminalId); if (!callbackTerminals || callbackTerminals.length === 0) { - this._disposables.push(this.terminalService.onDidOpenTerminal(this.onDidOpenTerminal.bind(this))); + this._disposables.add(this.terminalService.onDidOpenTerminal(this.onDidOpenTerminal.bind(this))); return; } @@ -462,9 +462,9 @@ class CustomExecutionData implements IDisposable { } this._cancellationSource = new CancellationTokenSource(); - this._disposables.push(this._cancellationSource); + this._disposables.add(this._cancellationSource); - this._disposables.push(this.terminalService.onDidCloseTerminal(this.onDidCloseTerminal.bind(this))); + this._disposables.add(this.terminalService.onDidCloseTerminal(this.onDidCloseTerminal.bind(this))); // Regardless of how the task completes, we are done with this custom execution task. this.customExecution.callback(terminalRenderer, this._cancellationSource.token).then( @@ -588,9 +588,7 @@ export class ExtHostTask implements ExtHostTaskShape { // Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task. this._activeCustomExecutions2.set(execution.id, execution2); - this._terminalService.performTerminalIdAction(terminalId, async terminal => { - this._terminalService.attachVirtualProcessToTerminal(terminalId, await execution2.callback()); - }); + await this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback()); } // Once a terminal is spun up for the custom execution task this event will be fired. diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index d9676b7dcef..58734d0827d 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -10,7 +10,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { Event, Emitter } from 'vs/base/common/event'; -import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; import { ILogService } from 'vs/platform/log/common/log'; import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -91,7 +91,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi this._idPromise.then(c => { this._proxy.$registerOnDataListener(this._id); }); - return this._onData && this._onData.event; + return this._onData.event; } constructor( @@ -110,7 +110,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi }); } - public create( + public async create( shellPath?: string, shellArgs?: string[] | string, cwd?: string | URI, @@ -118,18 +118,16 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi waitOnExit?: boolean, strictEnv?: boolean, hideFromUser?: boolean - ): void { - this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser }).then(terminal => { - this._name = terminal.name; - this._runQueuedRequests(terminal.id); - }); + ): Promise { + const terminal = await this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser }); + this._name = terminal.name; + this._runQueuedRequests(terminal.id); } - public createVirtualProcess(): Promise { - return this._proxy.$createTerminal({ name: this._name, isVirtualProcess: true }).then(terminal => { - this._name = terminal.name; - this._runQueuedRequests(terminal.id); - }); + public async createExtensionTerminal(): Promise { + const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true }); + this._name = terminal.name; + this._runQueuedRequests(terminal.id); } public get name(): string { @@ -286,6 +284,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {}; private _terminalRenderers: ExtHostTerminalRenderer[] = []; private _getTerminalPromises: { [id: number]: Promise } = {}; + private _variableResolver: ExtHostVariableResolverService | undefined; + private _lastActiveWorkspace: IWorkspaceFolder | undefined; // TODO: Pull this from main side private _isWorkspaceShellAllowed: boolean = false; @@ -307,9 +307,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { private _extHostConfiguration: ExtHostConfiguration, private _extHostWorkspace: ExtHostWorkspace, private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors, - private _logService: ILogService, + private _logService: ILogService ) { this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService); + this._updateLastActiveWorkspace(); + this._updateVariableResolver(); + this._registerListeners(); } public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { @@ -326,25 +329,21 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { return terminal; } - public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal { + public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { const terminal = new ExtHostTerminal(this._proxy, options.name); - const p = new ExtHostVirtualProcess(options.virtualProcess); - terminal.createVirtualProcess().then(() => { - this._setupExtHostProcessListeners(terminal._id, p); - p.startSendingEvents(); - }); + const p = new ExtHostPseudoterminal(options.pty); + terminal.createExtensionTerminal().then(() => this._setupExtHostProcessListeners(terminal._id, p)); this._terminals.push(terminal); return terminal; } - public attachVirtualProcessToTerminal(id: number, virtualProcess: vscode.TerminalVirtualProcess) { - const terminal = this._getTerminalById(id); + public async attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): Promise { + const terminal = this._getTerminalByIdEventually(id); if (!terminal) { throw new Error(`Cannot resolve terminal with id ${id} for virtual process`); } - const p = new ExtHostVirtualProcess(virtualProcess); + const p = new ExtHostPseudoterminal(pty); this._setupExtHostProcessListeners(id, p); - p.startSendingEvents(); } public createTerminalRenderer(name: string): vscode.TerminalRenderer { @@ -370,18 +369,21 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { this._isWorkspaceShellAllowed, getSystemShell(platform.platform), process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'), - process.env.windir + process.env.windir, + this._lastActiveWorkspace, + this._variableResolver ); } - private _getDefaultShellArgs(configProvider: ExtHostConfigProvider): string[] | string | undefined { + private _getDefaultShellArgs(configProvider: ExtHostConfigProvider): string[] | string { const fetchSetting = (key: string) => { const setting = configProvider .getConfiguration(key.substr(0, key.lastIndexOf('.'))) .inspect(key.substr(key.lastIndexOf('.') + 1)); return this._apiInspectConfigToPlain(setting); }; - return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed); + + return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, this._lastActiveWorkspace, this._variableResolver); } public async resolveTerminalRenderer(id: number): Promise { @@ -530,7 +532,25 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { return env; } - public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { + private _registerListeners(): void { + this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this._updateLastActiveWorkspace()); + this._extHostWorkspace.onDidChangeWorkspace(() => this._updateVariableResolver()); + } + + private _updateLastActiveWorkspace(): void { + const activeEditor = this._extHostDocumentsAndEditors.activeEditor(); + if (activeEditor) { + this._lastActiveWorkspace = this._extHostWorkspace.getWorkspaceFolder(activeEditor.document.uri) as IWorkspaceFolder; + } + } + + private async _updateVariableResolver(): Promise { + const configProvider = await this._extHostConfiguration.getConfigProvider(); + const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2(); + this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); + } + + public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { const shellLaunchConfig: IShellLaunchConfig = { name: shellLaunchConfigDto.name, executable: shellLaunchConfigDto.executable, @@ -545,6 +565,21 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { if (!shellLaunchConfig.executable) { shellLaunchConfig.executable = this.getDefaultShell(configProvider); shellLaunchConfig.args = this._getDefaultShellArgs(configProvider); + } else { + if (this._variableResolver) { + shellLaunchConfig.executable = this._variableResolver.resolve(this._lastActiveWorkspace, shellLaunchConfig.executable); + if (shellLaunchConfig.args) { + if (Array.isArray(shellLaunchConfig.args)) { + const resolvedArgs: string[] = []; + for (const arg of shellLaunchConfig.args) { + resolvedArgs.push(this._variableResolver.resolve(this._lastActiveWorkspace, arg)); + } + shellLaunchConfig.args = resolvedArgs; + } else { + shellLaunchConfig.args = this._variableResolver.resolve(this._lastActiveWorkspace, shellLaunchConfig.args); + } + } + } } // Get the initial cwd @@ -563,20 +598,19 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { } } as IWorkspaceFolder : null; const envFromConfig = this._apiInspectConfigToPlain(configProvider.getConfiguration('terminal.integrated').inspect(`env.${platformKey}`)); - const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2(); - const variableResolver = workspaceFolders ? new ExtHostVariableResolverService(workspaceFolders, this._extHostDocumentsAndEditors, configProvider) : undefined; const baseEnv = terminalConfig.get('inheritEnv', true) ? process.env as platform.IProcessEnvironment : await this._getNonInheritedEnv(); const env = terminalEnvironment.createTerminalEnvironment( shellLaunchConfig, lastActiveWorkspace, envFromConfig, - variableResolver, + this._variableResolver, isWorkspaceShellAllowed, pkg.version, terminalConfig.get('setLocaleVariables', false), baseEnv ); + this._proxy.$sendResolvedLaunchConfig(id, shellLaunchConfig); // Fork the process and listen for messages this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env); // TODO: Support conpty on remote, it doesn't seem to work for some reason? @@ -585,6 +619,24 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService)); } + public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise { + // Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call + // Pseudoterminal.start + await this._getTerminalByIdEventually(id); + + // Processes should be initialized here for normal virtual process terminals, however for + // tasks they are responsible for attaching the virtual process to a terminal so this + // function may be called before tasks is able to attach to the terminal. + let retries = 5; + while (retries-- > 0) { + if (this._terminalProcesses[id]) { + (this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions); + return; + } + await timeout(50); + } + } + private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void { p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd)); p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title)); @@ -721,49 +773,49 @@ class ApiRequest { } } -class ExtHostVirtualProcess implements ITerminalChildProcess { +class ExtHostPseudoterminal implements ITerminalChildProcess { private _queuedEvents: (IQueuedEvent | IQueuedEvent | IQueuedEvent<{ pid: number, cwd: string }> | IQueuedEvent)[] = []; private _queueDisposables: IDisposable[] | undefined; private readonly _onProcessData = new Emitter(); - public get onProcessData(): Event { return this._onProcessData.event; } + public readonly onProcessData: Event = this._onProcessData.event; private readonly _onProcessExit = new Emitter(); - public get onProcessExit(): Event { return this._onProcessExit.event; } + public readonly onProcessExit: Event = this._onProcessExit.event; private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>(); public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; } private readonly _onProcessTitleChanged = new Emitter(); - public get onProcessTitleChanged(): Event { return this._onProcessTitleChanged.event; } + public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; private readonly _onProcessOverrideDimensions = new Emitter(); public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } constructor( - private readonly _virtualProcess: vscode.TerminalVirtualProcess + private readonly _pty: vscode.Pseudoterminal ) { this._queueDisposables = []; - this._queueDisposables.push(this._virtualProcess.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); - if (this._virtualProcess.onDidExit) { - this._queueDisposables.push(this._virtualProcess.onDidExit(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: e }))); + this._queueDisposables.push(this._pty.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); + if (this._pty.onDidClose) { + this._queueDisposables.push(this._pty.onDidClose(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: 0 }))); } - if (this._virtualProcess.onDidOverrideDimensions) { - this._queueDisposables.push(this._virtualProcess.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); + if (this._pty.onDidOverrideDimensions) { + this._queueDisposables.push(this._pty.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); } } shutdown(): void { - if (this._virtualProcess.shutdown) { - this._virtualProcess.shutdown(); + if (this._pty.close) { + this._pty.close(); } } input(data: string): void { - if (this._virtualProcess.handleInput) { - this._virtualProcess.handleInput(data); + if (this._pty.handleInput) { + this._pty.handleInput(data); } } resize(cols: number, rows: number): void { - if (this._virtualProcess.setDimensions) { - this._virtualProcess.setDimensions({ columns: cols, rows }); + if (this._pty.setDimensions) { + this._pty.setDimensions({ columns: cols, rows }); } } @@ -779,23 +831,23 @@ class ExtHostVirtualProcess implements ITerminalChildProcess { return Promise.resolve(0); } - startSendingEvents(): void { + startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void { // Flush all buffered events this._queuedEvents.forEach(e => (e.emitter.fire)(e.data)); this._queuedEvents = []; this._queueDisposables = undefined; // Attach the real listeners - this._virtualProcess.onDidWrite(e => this._onProcessData.fire(e)); - if (this._virtualProcess.onDidExit) { - this._virtualProcess.onDidExit(e => this._onProcessExit.fire(e)); + this._pty.onDidWrite(e => this._onProcessData.fire(e)); + if (this._pty.onDidClose) { + this._pty.onDidClose(e => this._onProcessExit.fire(0)); } - if (this._virtualProcess.onDidOverrideDimensions) { - this._virtualProcess.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : e)); + if (this._pty.onDidOverrideDimensions) { + this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : e)); } - if (this._virtualProcess.start) { - this._virtualProcess.start(); + if (this._pty.open) { + this._pty.open(initialDimensions); } } } diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 84bf4619b0e..123e9a9b692 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -30,10 +30,10 @@ import { Disposable } from 'vs/base/common/lifecycle'; export abstract class Composite extends Component implements IComposite { private readonly _onTitleAreaUpdate: Emitter = this._register(new Emitter()); - get onTitleAreaUpdate(): Event { return this._onTitleAreaUpdate.event; } + readonly onTitleAreaUpdate: Event = this._onTitleAreaUpdate.event; private readonly _onDidChangeVisibility: Emitter = this._register(new Emitter()); - get onDidChangeVisibility(): Event { return this._onDidChangeVisibility.event; } + readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; private _onDidFocus: Emitter; get onDidFocus(): Event { diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 863626bdf48..b1de1c5bdc6 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -20,6 +20,7 @@ import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform'; import { PanelPositionContext } from 'vs/workbench/common/panel'; +import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; export const IsMacContext = new RawContextKey('isMac', isMacintosh); export const IsLinuxContext = new RawContextKey('isLinux', isLinux); @@ -28,8 +29,9 @@ export const IsWindowsContext = new RawContextKey('isWindows', isWindow export const IsWebContext = new RawContextKey('isWeb', isWeb); export const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb); -export const RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); +export const Deprecated_RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); +export const RemoteNameContext = new RawContextKey('remoteName', ''); export const RemoteConnectionState = new RawContextKey<'' | 'initializing' | 'disconnected' | 'connected'>('remoteConnectionState', ''); export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); @@ -121,7 +123,7 @@ export class WorkbenchContextKeysHandler extends Disposable { IsWebContext.bindTo(this.contextKeyService); IsMacNativeContext.bindTo(this.contextKeyService); - RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.environmentService.configuration.remoteAuthority || ''); + RemoteNameContext.bindTo(this.contextKeyService).set(getRemoteName(this.environmentService.configuration.remoteAuthority) || ''); // macOS Native Tabs const windowConfig = this.configurationService.getValue(); diff --git a/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts index a7f3c099ea2..e4add229a83 100644 --- a/src/vs/workbench/browser/editor.ts +++ b/src/vs/workbench/browser/editor.ts @@ -8,7 +8,6 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Registry } from 'vs/platform/registry/common/platform'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { isArray } from 'vs/base/common/types'; export interface IEditorDescriptor { instantiate(instantiationService: IInstantiationService): BaseEditor; @@ -27,26 +26,25 @@ export interface IEditorRegistry { * input, the input itself will be asked which editor it prefers if this method is provided. Otherwise * the first editor in the list will be returned. * - * @param editorInputDescriptor a constructor function that returns an instance of EditorInput for which the + * @param inputDescriptors A set of constructor functions that return an instance of EditorInput for which the * registered editor should be used for. */ - registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor): void; - registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor[]): void; + registerEditor(descriptor: IEditorDescriptor, inputDescriptors: readonly SyncDescriptor[]): void; /** - * Returns the editor descriptor for the given input or null if none. + * Returns the editor descriptor for the given input or `undefined` if none. */ - getEditor(input: EditorInput): IEditorDescriptor | null; + getEditor(input: EditorInput): IEditorDescriptor | undefined; /** - * Returns the editor descriptor for the given identifier or null if none. + * Returns the editor descriptor for the given identifier or `undefined` if none. */ - getEditorById(editorId: string): IEditorDescriptor | null; + getEditorById(editorId: string): IEditorDescriptor | undefined; /** * Returns an array of registered editors known to the platform. */ - getEditors(): IEditorDescriptor[]; + getEditors(): readonly IEditorDescriptor[]; } /** @@ -54,15 +52,12 @@ export interface IEditorRegistry { * can load lazily in the workbench. */ export class EditorDescriptor implements IEditorDescriptor { - private ctor: IConstructorSignature0; - private id: string; - private name: string; - constructor(ctor: IConstructorSignature0, id: string, name: string) { - this.ctor = ctor; - this.id = id; - this.name = name; - } + constructor( + private readonly ctor: IConstructorSignature0, + private readonly id: string, + private readonly name: string + ) { } instantiate(instantiationService: IInstantiationService): BaseEditor { return instantiationService.createInstance(this.ctor); @@ -84,47 +79,34 @@ export class EditorDescriptor implements IEditorDescriptor { class EditorRegistry implements IEditorRegistry { private editors: EditorDescriptor[] = []; - private readonly mapEditorToInputs = new Map[]>(); - - registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor): void; - registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor[]): void; - registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor | SyncDescriptor[]): void { - - // Support both non-array and array parameter - let inputDescriptors: SyncDescriptor[] = []; - if (!isArray(editorInputDescriptor)) { - inputDescriptors.push(editorInputDescriptor); - } else { - inputDescriptors = editorInputDescriptor; - } + private readonly mapEditorToInputs = new Map[]>(); + registerEditor(descriptor: EditorDescriptor, inputDescriptors: readonly SyncDescriptor[]): void { // Register (Support multiple Editors per Input) this.mapEditorToInputs.set(descriptor, inputDescriptors); this.editors.push(descriptor); } - getEditor(input: EditorInput): EditorDescriptor | null { + getEditor(input: EditorInput): EditorDescriptor | undefined { const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => { const matchingDescriptors: EditorDescriptor[] = []; for (const editor of this.editors) { - const inputDescriptors: SyncDescriptor[] | undefined = this.mapEditorToInputs.get(editor); - if (inputDescriptors) { - for (const inputDescriptor of inputDescriptors) { - const inputClass = inputDescriptor.ctor; + const inputDescriptors = this.mapEditorToInputs.get(editor) || []; + for (const inputDescriptor of inputDescriptors) { + const inputClass = inputDescriptor.ctor; - // Direct check on constructor type (ignores prototype chain) - if (!byInstanceOf && input.constructor === inputClass) { - matchingDescriptors.push(editor); - break; - } + // Direct check on constructor type (ignores prototype chain) + if (!byInstanceOf && input.constructor === inputClass) { + matchingDescriptors.push(editor); + break; + } - // Normal instanceof check - else if (byInstanceOf && input instanceof inputClass) { - matchingDescriptors.push(editor); - break; - } + // Normal instanceof check + else if (byInstanceOf && input instanceof inputClass) { + matchingDescriptors.push(editor); + break; } } } @@ -142,7 +124,7 @@ class EditorRegistry implements IEditorRegistry { }; const descriptors = findEditorDescriptors(input); - if (descriptors && descriptors.length > 0) { + if (descriptors.length > 0) { // Ask the input for its preferred Editor const preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId())); @@ -154,20 +136,20 @@ class EditorRegistry implements IEditorRegistry { return descriptors[0]; } - return null; + return undefined; } - getEditorById(editorId: string): EditorDescriptor | null { + getEditorById(editorId: string): EditorDescriptor | undefined { for (const editor of this.editors) { if (editor.getId() === editorId) { return editor; } } - return null; + return undefined; } - getEditors(): EditorDescriptor[] { + getEditors(): readonly EditorDescriptor[] { return this.editors.slice(0); } @@ -178,7 +160,7 @@ class EditorRegistry implements IEditorRegistry { getEditorInputs(): SyncDescriptor[] { const inputClasses: SyncDescriptor[] = []; for (const editor of this.editors) { - const editorInputDescriptors: SyncDescriptor[] | undefined = this.mapEditorToInputs.get(editor); + const editorInputDescriptors = this.mapEditorToInputs.get(editor); if (editorInputDescriptors) { inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor)); } diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 8742e98d27e..9db4979a3aa 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -239,7 +239,7 @@ enum Redraw { class ResourceLabelWidget extends IconLabel { private _onDidRender = this._register(new Emitter()); - get onDidRender(): Event { return this._onDidRender.event; } + readonly onDidRender: Event = this._onDidRender.event; private label?: IResourceLabelProps; private options?: IResourceLabelOptions; @@ -366,7 +366,7 @@ class ResourceLabelWidget extends IconLabel { this.setResource({ resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }), name: withNullAsUndefined(editor.getName()), - description: withNullAsUndefined(editor.getDescription(options ? options.descriptionVerbosity : undefined)) + description: editor.getDescription(options ? options.descriptionVerbosity : undefined) }, options); } diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 7e6bfaa4a30..cfbafeba3f6 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper, Dimension } from 'vs/base/browser/dom'; import { onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -27,7 +27,7 @@ import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid'; +import { Sizing, Direction, Grid, SerializableGrid, ISerializableView, ISerializedGrid, GridBranchNode, GridLeafNode, isGridBranchNode } from 'vs/base/browser/ui/grid/grid'; import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; @@ -52,9 +52,12 @@ enum Storage { PANEL_HIDDEN = 'workbench.panel.hidden', PANEL_POSITION = 'workbench.panel.location', + PANEL_SIZE_BEFORE_MAXIMIZED = 'workbench.panel.sizeBeforeMaximized', ZEN_MODE_ENABLED = 'workbench.zenmode.active', CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active', + + GRID_LAYOUT = 'workbench.grid.layout' } export abstract class Layout extends Disposable implements IWorkbenchLayoutService { @@ -62,22 +65,22 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi _serviceBrand: ServiceIdentifier; private readonly _onTitleBarVisibilityChange: Emitter = this._register(new Emitter()); - get onTitleBarVisibilityChange(): Event { return this._onTitleBarVisibilityChange.event; } + readonly onTitleBarVisibilityChange: Event = this._onTitleBarVisibilityChange.event; private readonly _onZenModeChange: Emitter = this._register(new Emitter()); - get onZenModeChange(): Event { return this._onZenModeChange.event; } + readonly onZenModeChange: Event = this._onZenModeChange.event; private readonly _onFullscreenChange: Emitter = this._register(new Emitter()); - get onFullscreenChange(): Event { return this._onFullscreenChange.event; } + readonly onFullscreenChange: Event = this._onFullscreenChange.event; private readonly _onCenteredLayoutChange: Emitter = this._register(new Emitter()); - get onCenteredLayoutChange(): Event { return this._onCenteredLayoutChange.event; } + readonly onCenteredLayoutChange: Event = this._onCenteredLayoutChange.event; private readonly _onPanelPositionChange: Emitter = this._register(new Emitter()); - get onPanelPositionChange(): Event { return this._onPanelPositionChange.event; } + readonly onPanelPositionChange: Event = this._onPanelPositionChange.event; private readonly _onLayout = this._register(new Emitter()); - get onLayout(): Event { return this._onLayout.event; } + readonly onLayout: Event = this._onLayout.event; private _dimension: IDimension; get dimension(): IDimension { return this._dimension; } @@ -87,16 +90,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private parts: Map = new Map(); - private workbenchGrid: Grid | WorkbenchLegacyLayout; + private workbenchGrid: SerializableGrid | WorkbenchLegacyLayout; private disposed: boolean; - private titleBarPartView: View; - private activityBarPartView: View; - private sideBarPartView: View; - private panelPartView: View; - private editorPartView: View; - private statusBarPartView: View; + private titleBarPartView: ISerializableView; + private activityBarPartView: ISerializableView; + private sideBarPartView: ISerializableView; + private panelPartView: ISerializableView; + private editorPartView: ISerializableView; + private statusBarPartView: ISerializableView; private environmentService: IWorkbenchEnvironmentService; private configurationService: IConfigurationService; @@ -140,9 +143,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi panel: { hidden: false, + sizeBeforeMaximize: 0, position: Position.BOTTOM, - height: 350, - width: 350, panelToRestore: undefined as string | undefined }, @@ -317,7 +319,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Layout if (this.workbenchGrid instanceof Grid) { if (!wasHidden) { - this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView); + this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView).width; } this.workbenchGrid.removeView(this.sideBarPartView); @@ -396,6 +398,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } } + // Panel size before maximized + this.state.panel.sizeBeforeMaximize = this.storageService.getNumber(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, StorageScope.GLOBAL, 0); + // Statusbar visibility this.state.statusBar.hidden = !this.configurationService.getValue(Settings.STATUSBAR_VISIBLE); @@ -540,6 +545,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return true; // any other part cannot be hidden } + getDimension(part: Parts): Dimension { + return this.getPart(part).dimension; + } + getTitleBarOffset(): number { let offset = 0; if (this.isVisible(Parts.TITLEBAR_PART)) { @@ -700,17 +709,84 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) { - // Create view wrappers for all parts - this.titleBarPartView = new View(titleBar); - this.sideBarPartView = new View(sideBar); - this.activityBarPartView = new View(activityBar); - this.editorPartView = new View(editorPart); - this.panelPartView = new View(panelPart); - this.statusBarPartView = new View(statusBar); + // View references for all parts + this.titleBarPartView = titleBar; + this.sideBarPartView = sideBar; + this.activityBarPartView = activityBar; + this.editorPartView = editorPart; + this.panelPartView = panelPart; + this.statusBarPartView = statusBar; - this.workbenchGrid = new Grid(this.editorPartView, { proportionalLayout: false }); + let workbenchGrid: SerializableGrid | undefined; - this.container.prepend(this.workbenchGrid.element); + const savedGrid = this.storageService.get(Storage.GRID_LAYOUT, StorageScope.GLOBAL, undefined); + if (savedGrid) { + const parsedGrid: ISerializedGrid = JSON.parse(savedGrid); + + const fromJSON = (serializedPart: { type: Parts } | null) => { + if (serializedPart && serializedPart.type) { + switch (serializedPart.type) { + case Parts.ACTIVITYBAR_PART: + return this.activityBarPartView; + case Parts.TITLEBAR_PART: + return this.titleBarPartView; + case Parts.EDITOR_PART: + return this.editorPartView; + case Parts.PANEL_PART: + return this.panelPartView; + case Parts.SIDEBAR_PART: + return this.sideBarPartView; + case Parts.STATUSBAR_PART: + return this.statusBarPartView; + default: + return this.editorPartView; + } + } else { + return this.editorPartView; + } + }; + + try { + workbenchGrid = SerializableGrid.deserialize(parsedGrid, { fromJSON }, { proportionalLayout: false }); + + const root = workbenchGrid.getViews(); + const middleSection = root.children[1] as GridBranchNode; + this.state.sideBar.position = (middleSection.children[0] as GridLeafNode).view === this.activityBarPartView ? Position.LEFT : Position.RIGHT; + this.state.panel.position = isGridBranchNode(middleSection.children[2]) ? Position.BOTTOM : Position.RIGHT; + } catch (err) { + console.error(err); + } + } + + if (!workbenchGrid) { + workbenchGrid = new SerializableGrid(this.editorPartView, { proportionalLayout: false }); + } + + this.container.prepend(workbenchGrid.element); + this.workbenchGrid = workbenchGrid; + + this._register((this.sideBarPartView as SidebarPart).onDidVisibilityChange((visible) => { + this.setSideBarHidden(!visible, true); + })); + + this._register((this.panelPartView as PanelPart).onDidVisibilityChange((visible) => { + this.setPanelHidden(!visible, true); + })); + + this._register((this.editorPartView as PanelPart).onDidVisibilityChange((visible) => { + this.setEditorHidden(!visible, true); + })); + + this._register(this.lifecycleService.onBeforeShutdown(beforeShutdownEvent => { + beforeShutdownEvent.veto(new Promise((resolve) => { + const grid = this.workbenchGrid as SerializableGrid; + const serializedGrid = grid.serialize(); + + this.storageService.store(Storage.GRID_LAYOUT, JSON.stringify(serializedGrid), StorageScope.GLOBAL); + + resolve(); + })); + })); } else { this.workbenchGrid = instantiationService.createInstance( WorkbenchLegacyLayout, @@ -767,8 +843,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi statusBarInGrid = true; } - if (!titlebarInGrid && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + if (!titlebarInGrid) { this.workbenchGrid.addView(this.titleBarPartView, Sizing.Split, this.editorPartView, Direction.Up); + titlebarInGrid = true; } @@ -783,65 +860,61 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } if (!panelInGrid) { - this.workbenchGrid.addView(this.panelPartView, this.getPanelDimension(this.state.panel.position) !== undefined ? this.getPanelDimension(this.state.panel.position) : Sizing.Split, this.editorPartView, this.state.panel.position === Position.BOTTOM ? Direction.Down : Direction.Right); + this.workbenchGrid.addView(this.panelPartView, Sizing.Split, this.editorPartView, this.state.panel.position === Position.BOTTOM ? Direction.Down : Direction.Right); panelInGrid = true; } // Hide parts if (this.state.panel.hidden) { - this.panelPartView.hide(); + this.workbenchGrid.setViewVisible(this.panelPartView, false); } if (this.state.statusBar.hidden) { - this.statusBarPartView.hide(); + this.workbenchGrid.setViewVisible(this.statusBarPartView, false); } - if (!this.isVisible(Parts.TITLEBAR_PART)) { - this.titleBarPartView.hide(); + if (titlebarInGrid && !this.isVisible(Parts.TITLEBAR_PART)) { + this.workbenchGrid.setViewVisible(this.titleBarPartView, false); } if (this.state.activityBar.hidden) { - this.activityBarPartView.hide(); + this.workbenchGrid.setViewVisible(this.activityBarPartView, false); } if (this.state.sideBar.hidden) { - this.sideBarPartView.hide(); + this.workbenchGrid.setViewVisible(this.sideBarPartView, false); } if (this.state.editor.hidden) { - this.editorPartView.hide(); + this.workbenchGrid.setViewVisible(this.editorPartView, false); } // Show visible parts if (!this.state.editor.hidden) { - this.editorPartView.show(); + this.workbenchGrid.setViewVisible(this.editorPartView, true); } if (!this.state.statusBar.hidden) { - this.statusBarPartView.show(); + this.workbenchGrid.setViewVisible(this.statusBarPartView, true); } if (this.isVisible(Parts.TITLEBAR_PART)) { - this.titleBarPartView.show(); + this.workbenchGrid.setViewVisible(this.titleBarPartView, true); } if (!this.state.activityBar.hidden) { - this.activityBarPartView.show(); + this.workbenchGrid.setViewVisible(this.activityBarPartView, true); } if (!this.state.sideBar.hidden) { - this.sideBarPartView.show(); + this.workbenchGrid.setViewVisible(this.sideBarPartView, true); } if (!this.state.panel.hidden) { - this.panelPartView.show(); + this.workbenchGrid.setViewVisible(this.panelPartView, true); } } - private getPanelDimension(position: Position): number { - return position === Position.BOTTOM ? this.state.panel.height : this.state.panel.width; - } - isEditorLayoutCentered(): boolean { return this.state.editor.centered; } @@ -869,22 +942,63 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } resizePart(part: Parts, sizeChange: number): void { - let view: View; - switch (part) { - case Parts.SIDEBAR_PART: - view = this.sideBarPartView; - case Parts.PANEL_PART: - view = this.panelPartView; - case Parts.EDITOR_PART: - view = this.editorPartView; - if (this.workbenchGrid instanceof Grid) { - this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange); - } else { - this.workbenchGrid.resizePart(part, sizeChange); - } - break; - default: - return; // Cannot resize other parts + if (this.workbenchGrid instanceof Grid) { + let viewSize; + const sizeChangePxWidth = this.workbenchGrid.width * sizeChange / 100; + const sizeChangePxHeight = this.workbenchGrid.height * sizeChange / 100; + + switch (part) { + case Parts.SIDEBAR_PART: + viewSize = this.workbenchGrid.getViewSize(this.sideBarPartView); + this.workbenchGrid.resizeView(this.sideBarPartView, + { + width: viewSize.width + sizeChangePxWidth, + height: viewSize.height + }); + + break; + case Parts.PANEL_PART: + viewSize = this.workbenchGrid.getViewSize(this.panelPartView); + + this.workbenchGrid.resizeView(this.panelPartView, + { + width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0), + height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight) + }); + + break; + case Parts.EDITOR_PART: + viewSize = this.workbenchGrid.getViewSize(this.editorPartView); + + // Single Editor Group + if (this.editorGroupService.count === 1) { + if (this.isVisible(Parts.SIDEBAR_PART)) { + this.workbenchGrid.resizeView(this.editorPartView, + { + width: viewSize.width + sizeChangePxWidth, + height: viewSize.height + }); + } else if (this.isVisible(Parts.PANEL_PART)) { + this.workbenchGrid.resizeView(this.editorPartView, + { + width: viewSize.width + (this.getPanelPosition() !== Position.BOTTOM ? sizeChangePxWidth : 0), + height: viewSize.height + (this.getPanelPosition() !== Position.BOTTOM ? 0 : sizeChangePxHeight) + }); + } + } else { + const activeGroup = this.editorGroupService.activeGroup; + + const { width, height } = this.editorGroupService.getSize(activeGroup); + this.editorGroupService.setSize(activeGroup, { width: width + sizeChangePxWidth, height: height + sizeChangePxHeight }); + } + + break; + default: + return; // Cannot resize other parts + } + } else { + // Legacy Layout + this.workbenchGrid.resizePart(part, sizeChange); } } @@ -1019,7 +1133,33 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi toggleMaximizedPanel(): void { if (this.workbenchGrid instanceof Grid) { - this.workbenchGrid.maximizeViewSize(this.panelPartView); + const curSize = this.workbenchGrid.getViewSize(this.panelPartView); + const size = { ...curSize }; + + if (!this.isPanelMaximized()) { + if (this.state.panel.position === Position.BOTTOM) { + size.height = this.panelPartView.maximumHeight; + this.state.panel.sizeBeforeMaximize = curSize.height; + } else { + size.width = this.panelPartView.maximumWidth; + this.state.panel.sizeBeforeMaximize = curSize.width; + } + + this.storageService.store(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, this.state.panel.sizeBeforeMaximize, StorageScope.GLOBAL); + } else { + if (this.state.panel.position === Position.BOTTOM) { + size.height = this.state.panel.sizeBeforeMaximize; + } else { + size.width = this.state.panel.sizeBeforeMaximize; + } + + // Unhide the editor if needed + if (this.state.editor.hidden) { + this.setEditorHidden(false); + } + } + + this.workbenchGrid.resizeView(this.panelPartView, size); } else { this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART }); } @@ -1028,7 +1168,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi isPanelMaximized(): boolean { if (this.workbenchGrid instanceof Grid) { try { - return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.getPart(Parts.PANEL_PART).maximumHeight; + // The panel is maximum when the editor is minimum + if (this.state.panel.position === Position.BOTTOM) { + return this.workbenchGrid.getViewSize(this.editorPartView).height <= this.editorPartView.minimumHeight; + } else { + return this.workbenchGrid.getViewSize(this.editorPartView).width <= this.editorPartView.minimumWidth; + } } catch (e) { return false; } @@ -1067,12 +1212,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi setPanelPosition(position: Position): void { const panelPart = this.getPart(Parts.PANEL_PART); - const wasHidden = this.state.panel.hidden; if (this.state.panel.hidden) { this.setPanelHidden(false, true /* Skip Layout */); - } else { - this.savePanelDimension(); } const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right'; @@ -1098,10 +1240,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Layout if (this.workbenchGrid instanceof Grid) { - if (!wasHidden) { - this.savePanelDimension(); - } - this.workbenchGrid.removeView(this.panelPartView); this.layout(); } else { @@ -1111,18 +1249,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this._onPanelPositionChange.fire(positionToString(this.state.panel.position)); } - private savePanelDimension(): void { - if (!(this.workbenchGrid instanceof Grid)) { - return; - } - - if (this.state.panel.position === Position.BOTTOM) { - this.state.panel.height = this.workbenchGrid.getViewSize(this.panelPartView); - } else { - this.state.panel.width = this.workbenchGrid.getViewSize(this.panelPartView); - } - } - dispose(): void { super.dispose(); diff --git a/src/vs/workbench/browser/legacyLayout.ts b/src/vs/workbench/browser/legacyLayout.ts index a1d936c0f1e..8800afc09e8 100644 --- a/src/vs/workbench/browser/legacyLayout.ts +++ b/src/vs/workbench/browser/legacyLayout.ts @@ -626,11 +626,11 @@ export class WorkbenchLegacyLayout extends Disposable implements IVerticalSashLa } // Propagate to Part Layouts - this.parts.titlebar.layout(this.workbenchSize.width, this.titlebarHeight, -1); - this.parts.editor.layout(editorSize.width, editorSize.height, -1); - this.parts.sidebar.layout(sidebarSize.width, sidebarSize.height, -1); - this.parts.panel.layout(panelDimension.width, panelDimension.height, -1); - this.parts.activitybar.layout(activityBarSize.width, activityBarSize.height, -1); + this.parts.titlebar.layout(this.workbenchSize.width, this.titlebarHeight); + this.parts.editor.layout(editorSize.width, editorSize.height); + this.parts.sidebar.layout(sidebarSize.width, sidebarSize.height); + this.parts.panel.layout(panelDimension.width, panelDimension.height); + this.parts.activitybar.layout(activityBarSize.width, activityBarSize.height); // Propagate to Context View this.contextViewService.layout(); @@ -726,8 +726,8 @@ export class WorkbenchLegacyLayout extends Disposable implements IVerticalSashLa } else { const activeGroup = this.editorGroupService.activeGroup; - const activeGroupSize = this.editorGroupService.getSize(activeGroup); - this.editorGroupService.setSize(activeGroup, activeGroupSize + sizeChangePxWidth); + const { width, height } = this.editorGroupService.getSize(activeGroup); + this.editorGroupService.setSize(activeGroup, { width: width + sizeChangePxWidth, height: height + sizeChangePxHeight }); } } diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index 3822e23e4ea..c78ad168cb7 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -9,7 +9,7 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Dimension, size } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; -import { ISerializableView, Orientation } from 'vs/base/browser/ui/grid/grid'; +import { ISerializableView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -28,6 +28,10 @@ export interface ILayoutContentResult { * arranges an optional title and mandatory content area to show content. */ export abstract class Part extends Component implements ISerializableView { + + private _dimension: Dimension; + get dimension(): Dimension { return this._dimension; } + private parent: HTMLElement; private titleArea: HTMLElement | null; private contentArea: HTMLElement | null; @@ -117,8 +121,8 @@ export abstract class Part extends Component implements ISerializableView { //#region ISerializableView - private _onDidChange = this._register(new Emitter<{ width: number; height: number; }>()); - get onDidChange(): Event<{ width: number, height: number }> { return this._onDidChange.event; } + private _onDidChange = this._register(new Emitter()); + get onDidChange(): Event { return this._onDidChange.event; } element: HTMLElement; @@ -127,7 +131,10 @@ export abstract class Part extends Component implements ISerializableView { abstract minimumHeight: number; abstract maximumHeight: number; - abstract layout(width: number, height: number, orientation: Orientation): void; + layout(width: number, height: number): void { + this._dimension = new Dimension(width, height); + } + abstract toJSON(): object; //#endregion @@ -163,4 +170,4 @@ class PartLayout { return { titleSize, contentSize }; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 873dc45aadf..d73545fb3ef 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -72,13 +72,11 @@ export class ViewletActivityAction extends ActivityAction { } private logAction(action: string) { - /* __GDPR__ - "activityBarAction" : { - "viewletId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "action": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('activityBarAction', { viewletId: this.activity.id, action }); + type ActivityBarActionClassification = { + viewletId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + action: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ viewletId: String, action: String }, ActivityBarActionClassification>('activityBarAction', { viewletId: this.activity.id, action }); } } @@ -165,7 +163,7 @@ export class GlobalActivityActionViewItem extends ActivityActionViewItem { export class PlaceHolderViewletActivityAction extends ViewletActivityAction { constructor( - id: string, iconUrl: URI, + id: string, name: string, iconUrl: URI, @IViewletService viewletService: IViewletService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ITelemetryService telemetryService: ITelemetryService diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 430a560f520..c8ce2bc031f 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -34,9 +34,11 @@ import { isUndefinedOrNull } from 'vs/base/common/types'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Schemas } from 'vs/base/common/network'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; interface ICachedViewlet { id: string; + name?: string; iconUrl?: UriComponents; pinned: boolean; order?: number; @@ -78,18 +80,23 @@ export class ActivitybarPart extends Part implements IActivityBarService { @IStorageService private readonly storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, @IViewsService private readonly viewsService: IViewsService, - @IContextKeyService private readonly contextKeyService: IContextKeyService + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); this.cachedViewlets = this.getCachedViewlets(); for (const cachedViewlet of this.cachedViewlets) { - if (this.shouldBeHidden(cachedViewlet.id, cachedViewlet)) { + if (workbenchEnvironmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered. + || this.shouldBeHidden(cachedViewlet.id, cachedViewlet) + ) { cachedViewlet.visible = false; } } - this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.cachedViewlets.map(v => ({ id: v.id, name: undefined, visible: v.visible, order: v.order, pinned: v.pinned })), { + const cachedItems = this.cachedViewlets + .map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned })); + this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { icon: true, orientation: ActionsOrientation.VERTICAL, openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), @@ -252,7 +259,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } else { const cachedComposite = this.cachedViewlets.filter(c => c.id === compositeId)[0]; compositeActions = { - activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.iconUrl ? URI.revive(cachedComposite.iconUrl) : undefined), + activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.name ? cachedComposite.name : compositeId, cachedComposite && cachedComposite.iconUrl ? URI.revive(cachedComposite.iconUrl) : undefined), pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar) }; } @@ -312,7 +319,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } - private shouldBeHidden(viewletId: string, cachedViewlet: ICachedViewlet): boolean { + private shouldBeHidden(viewletId: string, cachedViewlet?: ICachedViewlet): boolean { const viewContainer = this.getViewContainer(viewletId); if (!viewContainer || !viewContainer.hideIfEmpty) { return false; @@ -428,7 +435,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } } - state.push({ id: compositeItem.id, iconUrl: viewlet.iconUrl && viewlet.iconUrl.scheme === Schemas.file ? viewlet.iconUrl : undefined, views, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); + state.push({ id: compositeItem.id, name: viewlet.name, iconUrl: viewlet.iconUrl && viewlet.iconUrl.scheme === Schemas.file ? viewlet.iconUrl : undefined, views, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); } else { state.push({ id: compositeItem.id, pinned: compositeItem.pinned, order: compositeItem.order, visible: false }); } @@ -440,7 +447,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private getCachedViewlets(): ICachedViewlet[] { const storedStates: Array = JSON.parse(this.cachedViewletsValue); const cachedViewlets = storedStates.map(c => { - const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, iconUrl: undefined, views: undefined } : c; + const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, iconUrl: undefined, views: undefined } : c; serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible; return serialized; }); @@ -448,6 +455,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { for (const old of this.loadOldCachedViewlets()) { const cachedViewlet = cachedViewlets.filter(cached => cached.id === old.id)[0]; if (cachedViewlet) { + cachedViewlet.name = old.name; cachedViewlet.iconUrl = old.iconUrl; cachedViewlet.views = old.views; } diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index fe21d315410..d3445a9bbb6 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -52,10 +52,10 @@ export interface ICompositeBar { export class ActivityAction extends Action { private _onDidChangeActivity = new Emitter(); - get onDidChangeActivity(): Event { return this._onDidChangeActivity.event; } + readonly onDidChangeActivity: Event = this._onDidChangeActivity.event; private _onDidChangeBadge = new Emitter(); - get onDidChangeBadge(): Event { return this._onDidChangeBadge.event; } + readonly onDidChangeBadge: Event = this._onDidChangeBadge.event; private badge?: IBadge; private clazz: string | undefined; diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index d09cf93901b..e5d7cfbe7c8 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -466,6 +466,7 @@ export abstract class CompositePart extends Part { } layout(width: number, height: number): void { + super.layout(width, height); // Layout contents this.contentAreaSize = super.layoutContents(width, height).contentSize; diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index b2d51bde13c..81a6096128b 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -33,10 +33,10 @@ export interface IOpenCallbacks { export abstract class BaseBinaryResourceEditor extends BaseEditor { private readonly _onMetadataChanged: Emitter = this._register(new Emitter()); - get onMetadataChanged(): Event { return this._onMetadataChanged.event; } + readonly onMetadataChanged: Event = this._onMetadataChanged.event; private readonly _onDidOpenInPlace: Emitter = this._register(new Emitter()); - get onDidOpenInPlace(): Event { return this._onDidOpenInPlace.event; } + readonly onDidOpenInPlace: Event = this._onDidOpenInPlace.event; private callbacks: IOpenCallbacks; private metadata: string | undefined; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 85bb27482fc..0614722d536 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -304,12 +304,10 @@ export class BreadcrumbsControl { const { element } = event.item as Item; this._editorGroup.focus(); - /* __GDPR__ - "breadcrumbs/select" : { - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this._telemetryService.publicLog('breadcrumbs/select', { type: element instanceof TreeElement ? 'symbol' : 'file' }); + type BreadcrumbSelectClassification = { + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this._telemetryService.publicLog2<{ type: string }, BreadcrumbSelectClassification>('breadcrumbs/select', { type: element instanceof TreeElement ? 'symbol' : 'file' }); const group = this._getEditorGroup(event.payload); if (group !== undefined) { diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index 7d0376877c1..42ca9e2d502 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -9,7 +9,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { createMatches, FuzzyScore } from 'vs/base/common/filters'; import * as glob from 'vs/base/common/glob'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { posix } from 'vs/base/common/path'; import { basename, dirname, isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; @@ -25,10 +25,9 @@ import { ResourceLabels, IResourceLabel, DEFAULT_LABELS_CONTAINER } from 'vs/wor import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs'; import { BreadcrumbElement, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel'; import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeFilter, TreeVisibility, ITreeSorter, IDataSource } from 'vs/base/browser/ui/tree/tree'; -import { OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItemComparator, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineDataSource, OutlineSortOrder, OutlineItem } from 'vs/editor/contrib/documentSymbols/outlineTree'; +import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeFilter, TreeVisibility, ITreeSorter } from 'vs/base/browser/ui/tree/tree'; +import { OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItemComparator, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineDataSource, OutlineSortOrder } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { IIdentityProvider, IListVirtualDelegate, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list'; -import { IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree'; export function createBreadcrumbsPicker(instantiationService: IInstantiationService, parent: HTMLElement, element: BreadcrumbElement): BreadcrumbsPicker { const ctor: IConstructorSignature1 = element instanceof FileElement @@ -55,7 +54,7 @@ export interface SelectEvent { export abstract class BreadcrumbsPicker { - protected readonly _disposables = new Array(); + protected readonly _disposables = new DisposableStore(); protected readonly _domNode: HTMLDivElement; protected _arrow: HTMLDivElement; protected _treeContainer: HTMLDivElement; @@ -81,7 +80,7 @@ export abstract class BreadcrumbsPicker { } dispose(): void { - dispose(this._disposables); + this._disposables.dispose(); this._onDidPickElement.dispose(); this._tree.dispose(); } @@ -105,7 +104,7 @@ export abstract class BreadcrumbsPicker { this._layoutInfo = { maxHeight, width, arrowSize, arrowOffset, inputHeight: 0 }; this._tree = this._createTree(this._treeContainer); - this._disposables.push(this._tree.onDidChangeSelection(e => { + this._disposables.add(this._tree.onDidChangeSelection(e => { if (e.browserEvent !== this._fakeEvent) { const target = this._getTargetFromEvent(e.elements[0]); if (target) { @@ -115,13 +114,13 @@ export abstract class BreadcrumbsPicker { } } })); - this._disposables.push(this._tree.onDidChangeFocus(e => { + this._disposables.add(this._tree.onDidChangeFocus(e => { const target = this._getTargetFromEvent(e.elements[0]); if (target) { this._onDidFocusElement.fire({ target, browserEvent: e.browserEvent || new UIEvent('fake') }); } })); - this._disposables.push(this._tree.onDidChangeContentHeight(() => { + this._disposables.add(this._tree.onDidChangeContentHeight(() => { this._layout(); })); @@ -276,7 +275,7 @@ class FileNavigationLabelProvider implements IKeyboardNavigationLabelProvider { private readonly _cachedExpressions = new Map(); - private readonly _disposables: IDisposable[] = []; + private readonly _disposables = new DisposableStore(); constructor( @IWorkspaceContextService private readonly _workspaceService: IWorkspaceContextService, @@ -306,15 +305,13 @@ class FileFilter implements ITreeFilter { }); }; update(); - this._disposables.push( - config, - config.onDidChange(update), - _workspaceService.onDidChangeWorkspaceFolders(update) - ); + this._disposables.add(config); + this._disposables.add(config.onDidChange(update)); + this._disposables.add(_workspaceService.onDidChangeWorkspaceFolders(update)); } dispose(): void { - dispose(this._disposables); + this._disposables.dispose(); } filter(element: IWorkspaceFolder | IFileStat, _parentVisibility: TreeVisibility): boolean { @@ -371,11 +368,11 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { dom.toggleClass(this._treeContainer, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons); dom.toggleClass(this._treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true); }; - this._disposables.push(this._themeService.onDidFileIconThemeChange(onFileIconThemeChange)); + this._disposables.add(this._themeService.onDidFileIconThemeChange(onFileIconThemeChange)); onFileIconThemeChange(this._themeService.getFileIconTheme()); const labels = this._instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER /* TODO@Jo visibility propagation */); - this._disposables.push(labels); + this._disposables.add(labels); return this._instantiationService.createInstance(WorkbenchAsyncDataTree, container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), { multipleSelectionSupport: false, @@ -383,7 +380,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { filter: this._instantiationService.createInstance(FileFilter), identityProvider: new FileIdentityProvider(), keyboardNavigationLabelProvider: new FileNavigationLabelProvider() - }) as WorkbenchAsyncDataTree; + }); } _setInput(element: BreadcrumbElement): Promise { @@ -441,14 +438,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { } protected _createTree(container: HTMLElement) { - return this._instantiationService.createInstance< - HTMLElement, - IListVirtualDelegate, - ITreeRenderer[], - IDataSource, - IDataTreeOptions, - WorkbenchDataTree - >( + return this._instantiationService.createInstance( WorkbenchDataTree, container, new OutlineVirtualDelegate(), @@ -461,7 +451,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { identityProvider: new OutlineIdentityProvider(), keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider() } - ) as WorkbenchDataTree; + ); } dispose(): void { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index c10e7979ba0..354ef330025 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -51,6 +51,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { toLocalResource } from 'vs/base/common/resources'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { withNullAsUndefined } from 'vs/base/common/types'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -205,7 +206,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory { const masterInput = masterInputFactory.deserialize(instantiationService, deserialized.masterSerialized); if (detailsInput && masterInput) { - return new SideBySideEditorInput(deserialized.name, deserialized.description, detailsInput, masterInput); + return new SideBySideEditorInput(deserialized.name, withNullAsUndefined(deserialized.description), detailsInput, masterInput); } } @@ -447,7 +448,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands. interface IEditorToolItem { id: string; title: string; iconDark: string; iconLight: string; } -function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr, order: number, alternative?: IEditorToolItem): void { +function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem): void { const item: IMenuItem = { command: { id: primary.id, diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index ae8928e6b49..638c44e147e 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -443,11 +443,11 @@ export function splitEditor(editorGroupService: IEditorGroupsService, direction: const newGroup = editorGroupService.addGroup(sourceGroup, direction); // Split editor (if it can be split) - let editorToCopy: IEditorInput | null; + let editorToCopy: IEditorInput | undefined; if (context && typeof context.editorIndex === 'number') { editorToCopy = sourceGroup.getEditor(context.editorIndex); } else { - editorToCopy = sourceGroup.activeEditor; + editorToCopy = types.withNullAsUndefined(sourceGroup.activeEditor); } if (editorToCopy && (editorToCopy as EditorInput).supportsSplitEditor()) { diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 3db5b69060b..726b84c97db 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -30,7 +30,7 @@ export class EditorControl extends Disposable { get maximumHeight() { return this._activeControl ? this._activeControl.maximumHeight : DEFAULT_EDITOR_MAX_DIMENSIONS.height; } private readonly _onDidFocus: Emitter = this._register(new Emitter()); - get onDidFocus(): Event { return this._onDidFocus.event; } + readonly onDidFocus: Event = this._onDidFocus.event; private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; } | undefined>()); get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return this._onDidSizeConstraintsChange.event; } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index a1c4176be56..e5cc3843429 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -44,7 +44,7 @@ import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/m import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { isErrorWithActions, IErrorWithActions } from 'vs/base/common/errorsWithActions'; import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { hash } from 'vs/base/common/hash'; import { guessMimeTypes } from 'vs/base/common/mime'; import { extname } from 'vs/base/common/resources'; @@ -71,25 +71,25 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region events private readonly _onDidFocus: Emitter = this._register(new Emitter()); - get onDidFocus(): Event { return this._onDidFocus.event; } + readonly onDidFocus: Event = this._onDidFocus.event; private readonly _onWillDispose: Emitter = this._register(new Emitter()); - get onWillDispose(): Event { return this._onWillDispose.event; } + readonly onWillDispose: Event = this._onWillDispose.event; private readonly _onDidGroupChange: Emitter = this._register(new Emitter()); - get onDidGroupChange(): Event { return this._onDidGroupChange.event; } + readonly onDidGroupChange: Event = this._onDidGroupChange.event; private readonly _onWillOpenEditor: Emitter = this._register(new Emitter()); - get onWillOpenEditor(): Event { return this._onWillOpenEditor.event; } + readonly onWillOpenEditor: Event = this._onWillOpenEditor.event; private readonly _onDidOpenEditorFail: Emitter = this._register(new Emitter()); - get onDidOpenEditorFail(): Event { return this._onDidOpenEditorFail.event; } + readonly onDidOpenEditorFail: Event = this._onDidOpenEditorFail.event; private readonly _onWillCloseEditor: Emitter = this._register(new Emitter()); - get onWillCloseEditor(): Event { return this._onWillCloseEditor.event; } + readonly onWillCloseEditor: Event = this._onWillCloseEditor.event; private readonly _onDidCloseEditor: Emitter = this._register(new Emitter()); - get onDidCloseEditor(): Event { return this._onDidCloseEditor.event; } + readonly onDidCloseEditor: Event = this._onDidCloseEditor.event; //#endregion @@ -729,7 +729,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return this.editors; } - getEditor(index: number): EditorInput | null { + getEditor(index: number): EditorInput | undefined { return this._group.getEditor(index); } @@ -789,10 +789,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Proceed with opening - return this.doOpenEditor(editor, options); + return this.doOpenEditor(editor, options).then(withUndefinedAsNull); } - private doOpenEditor(editor: EditorInput, options?: EditorOptions): Promise { + private doOpenEditor(editor: EditorInput, options?: EditorOptions): Promise { // Determine options const openEditorOptions: IEditorOpenOptions = { @@ -833,10 +833,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return this.doShowEditor(editor, !!openEditorOptions.active, options); } - private async doShowEditor(editor: EditorInput, active: boolean, options?: EditorOptions): Promise { + private async doShowEditor(editor: EditorInput, active: boolean, options?: EditorOptions): Promise { // Show in editor control if the active editor changed - let openEditorPromise: Promise; + let openEditorPromise: Promise; if (active) { openEditorPromise = (async () => { try { @@ -853,11 +853,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Handle errors but do not bubble them up this.doHandleOpenEditorError(error, editor, options); - return null; // error: return NULL as result to signal this + return undefined; // error: return undefined as result to signal this } })(); } else { - openEditorPromise = Promise.resolve(null); // inactive: return NULL as result to signal this + openEditorPromise = Promise.resolve(undefined); // inactive: return undefined as result to signal this } // Show in title control after editor control because some actions depend on it diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 810b2aa3ab7..3d456d54ecc 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -11,7 +11,7 @@ import { Event, Emitter, Relay } from 'vs/base/common/event'; import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; +import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorPartOptions } from 'vs/workbench/common/editor'; import { values } from 'vs/base/common/map'; import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme'; @@ -27,7 +27,6 @@ import { EditorDropTarget } from 'vs/workbench/browser/parts/editor/editorDropTa import { localize } from 'vs/nls'; import { Color } from 'vs/base/common/color'; import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout'; -import { IView, orthogonal, LayoutPriority } from 'vs/base/browser/ui/grid/gridview'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -91,34 +90,32 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region Events private readonly _onDidLayout: Emitter = this._register(new Emitter()); - get onDidLayout(): Event { return this._onDidLayout.event; } + readonly onDidLayout: Event = this._onDidLayout.event; private readonly _onDidActiveGroupChange: Emitter = this._register(new Emitter()); - get onDidActiveGroupChange(): Event { return this._onDidActiveGroupChange.event; } + readonly onDidActiveGroupChange: Event = this._onDidActiveGroupChange.event; private readonly _onDidActivateGroup: Emitter = this._register(new Emitter()); - get onDidActivateGroup(): Event { return this._onDidActivateGroup.event; } + readonly onDidActivateGroup: Event = this._onDidActivateGroup.event; private readonly _onDidAddGroup: Emitter = this._register(new Emitter()); - get onDidAddGroup(): Event { return this._onDidAddGroup.event; } + readonly onDidAddGroup: Event = this._onDidAddGroup.event; private readonly _onDidRemoveGroup: Emitter = this._register(new Emitter()); - get onDidRemoveGroup(): Event { return this._onDidRemoveGroup.event; } + readonly onDidRemoveGroup: Event = this._onDidRemoveGroup.event; private readonly _onDidMoveGroup: Emitter = this._register(new Emitter()); - get onDidMoveGroup(): Event { return this._onDidMoveGroup.event; } + readonly onDidMoveGroup: Event = this._onDidMoveGroup.event; private onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>()); private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>()); get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); } - private readonly _onDidPreferredSizeChange: Emitter = this._register(new Emitter()); - get onDidPreferredSizeChange(): Event { return this._onDidPreferredSizeChange.event; } + private _onDidVisibilityChange = this._register(new Emitter()); + readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; //#endregion - private _preferredSize: Dimension | undefined; - private readonly workspaceMemento: MementoObject; private readonly globalMemento: MementoObject; @@ -162,7 +159,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private enforcedPartOptions: IEditorPartOptions[] = []; private readonly _onDidEditorPartOptionsChange: Emitter = this._register(new Emitter()); - get onDidEditorPartOptionsChange(): Event { return this._onDidEditorPartOptionsChange.event; } + readonly onDidEditorPartOptionsChange: Event = this._onDidEditorPartOptionsChange.event; private registerListeners(): void { this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); @@ -205,8 +202,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region IEditorGroupsService - private _dimension: Dimension; - get dimension(): Dimension { return this._dimension; } + private _contentDimension: Dimension; + get contentDimension(): Dimension { return this._contentDimension; } get activeGroup(): IEditorGroupView { return this._activeGroup; @@ -326,13 +323,13 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro return groupView; } - getSize(group: IEditorGroupView | GroupIdentifier): number { + getSize(group: IEditorGroupView | GroupIdentifier): { width: number, height: number } { const groupView = this.assertGroupView(group); return this.gridWidget.getViewSize(groupView); } - setSize(group: IEditorGroupView | GroupIdentifier, size: number): void { + setSize(group: IEditorGroupView | GroupIdentifier, size: { width: number, height: number }): void { const groupView = this.assertGroupView(group); this.gridWidget.resizeView(groupView, size); @@ -366,9 +363,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro const newOrientation = (orientation === GroupOrientation.HORIZONTAL) ? Orientation.HORIZONTAL : Orientation.VERTICAL; if (this.gridWidget.orientation !== newOrientation) { this.gridWidget.orientation = newOrientation; - - // Mark preferred size as changed - this.resetPreferredSize(); } } @@ -418,14 +412,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro this.doCreateGridControlWithState(gridDescriptor, activeGroup.id, currentGroupViews); // Layout - this.doLayout(this._dimension); + this.doLayout(this._contentDimension); // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Events for groups that got added this.getGroups(GroupsOrder.GRID_APPEARANCE).forEach(groupView => { if (currentGroupViews.indexOf(groupView) === -1) { @@ -490,9 +481,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Event this._onDidAddGroup.fire(newGroupView); @@ -564,7 +552,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Maximize the group if it is currently minimized if (this.gridWidget) { - const viewSize = this.gridWidget.getViewSize2(group); + const viewSize = this.gridWidget.getViewSize(group); if (viewSize.width === group.minimumWidth || viewSize.height === group.minimumHeight) { this.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS); } @@ -661,9 +649,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Event this._onDidRemoveGroup.fire(groupView); } @@ -756,29 +741,15 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region Part - readonly priority: LayoutPriority = LayoutPriority.High; - get minimumWidth(): number { return this.centeredLayoutWidget.minimumWidth; } get maximumWidth(): number { return this.centeredLayoutWidget.maximumWidth; } get minimumHeight(): number { return this.centeredLayoutWidget.minimumHeight; } get maximumHeight(): number { return this.centeredLayoutWidget.maximumHeight; } - get preferredSize(): Dimension { - if (!this._preferredSize) { - this._preferredSize = new Dimension(this.gridWidget.minimumWidth, this.gridWidget.minimumHeight); - } + readonly snap = true; - return this._preferredSize; - } - - private resetPreferredSize(): void { - - // Reset (will be computed upon next access) - this._preferredSize = undefined; - - // Event - this._onDidPreferredSizeChange.fire(); - } + get onDidChange(): Event { return this.centeredLayoutWidget.onDidChange; } + readonly priority: LayoutPriority = LayoutPriority.High; private get gridSeparatorBorder(): Color { return this.theme.getColor(EDITOR_GROUP_BORDER) || this.theme.getColor(contrastBorder) || Color.transparent; @@ -967,10 +938,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } private doLayout(dimension: Dimension): void { - this._dimension = dimension; + this._contentDimension = dimension; // Layout Grid - this.centeredLayoutWidget.layout(this._dimension.width, this._dimension.height); + this.centeredLayoutWidget.layout(this._contentDimension.width, this._contentDimension.height); // Event this._onDidLayout.fire(dimension); @@ -1020,6 +991,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#endregion + setVisible(visible: boolean): void { + this._onDidVisibilityChange.fire(visible); + } + toJSON(): object { return { type: Parts.EDITOR_PART @@ -1027,4 +1002,4 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } } -registerSingleton(IEditorGroupsService, EditorPart); \ No newline at end of file +registerSingleton(IEditorGroupsService, EditorPart); diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index 6b30c32d092..a3d495473f5 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -59,7 +59,7 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { } getDescription() { - return withNullAsUndefined(this.editor.getDescription()); + return this.editor.getDescription(); } run(mode: Mode, context: IEntryRunContext): boolean { diff --git a/src/vs/workbench/browser/parts/editor/editorWidgets.ts b/src/vs/workbench/browser/parts/editor/editorWidgets.ts index de5aacf5354..d0595046aaa 100644 --- a/src/vs/workbench/browser/parts/editor/editorWidgets.ts +++ b/src/vs/workbench/browser/parts/editor/editorWidgets.ts @@ -24,7 +24,7 @@ import { IFileService } from 'vs/platform/files/common/files'; export class FloatingClickWidget extends Widget implements IOverlayWidget { private readonly _onClick: Emitter = this._register(new Emitter()); - get onClick(): Event { return this._onClick.event; } + readonly onClick: Event = this._onClick.event; private _domNode: HTMLElement; diff --git a/src/vs/workbench/browser/parts/editor/rangeDecorations.ts b/src/vs/workbench/browser/parts/editor/rangeDecorations.ts index 0e994f72c34..4c52be6ca69 100644 --- a/src/vs/workbench/browser/parts/editor/rangeDecorations.ts +++ b/src/vs/workbench/browser/parts/editor/rangeDecorations.ts @@ -26,7 +26,7 @@ export class RangeHighlightDecorations extends Disposable { private readonly editorDisposables = this._register(new DisposableStore()); private readonly _onHighlightRemoved: Emitter = this._register(new Emitter()); - get onHighlightRemoved(): Event { return this._onHighlightRemoved.event; } + readonly onHighlightRemoved: Event = this._onHighlightRemoved.event; constructor(@IEditorService private readonly editorService: IEditorService) { super(); diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 7af89021113..6a8daa4b094 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -695,7 +695,7 @@ export class TabsTitleControl extends TitleControl { private updateDropFeedback(element: HTMLElement, isDND: boolean, index?: number): void { const isTab = (typeof index === 'number'); - const editor = typeof index === 'number' ? this.group.getEditor(index) : null; + const editor = typeof index === 'number' ? this.group.getEditor(index) : undefined; const isActiveTab = isTab && !!editor && this.group.isActive(editor); // Background @@ -725,7 +725,7 @@ export class TabsTitleControl extends TitleControl { const labels = this.group.editors.map(editor => ({ editor, name: editor.getName()!, - description: withNullAsUndefined(editor.getDescription(verbosity)), + description: editor.getDescription(verbosity), title: withNullAsUndefined(editor.getTitle(Verbosity.LONG)) })); @@ -778,7 +778,7 @@ export class TabsTitleControl extends TitleControl { if (useLongDescriptions) { mapDescriptionToDuplicates.clear(); duplicateTitles.forEach(label => { - label.description = withNullAsUndefined(label.editor.getDescription(Verbosity.LONG)); + label.description = label.editor.getDescription(Verbosity.LONG); getOrSet(mapDescriptionToDuplicates, label.description, []).push(label); }); } diff --git a/src/vs/workbench/browser/parts/notifications/media/error.svg b/src/vs/workbench/browser/parts/notifications/media/error.svg deleted file mode 100755 index 04b66689011..00000000000 --- a/src/vs/workbench/browser/parts/notifications/media/error.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/vs/workbench/browser/parts/notifications/media/info.svg b/src/vs/workbench/browser/parts/notifications/media/info.svg deleted file mode 100755 index 3c603528a74..00000000000 --- a/src/vs/workbench/browser/parts/notifications/media/info.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/workbench/browser/parts/notifications/media/warning.svg b/src/vs/workbench/browser/parts/notifications/media/warning.svg deleted file mode 100755 index 6d8cffe913e..00000000000 --- a/src/vs/workbench/browser/parts/notifications/media/warning.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - -StatusWarning_16x - - - - - diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index c4ef92629a4..16f7f408a3e 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -145,9 +145,7 @@ export class CopyNotificationMessageAction extends Action { } run(notification: INotificationViewItem): Promise { - this.clipboardService.writeText(notification.message.raw); - - return Promise.resolve(); + return this.clipboardService.writeText(notification.message.raw); } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index e06e38cde64..adef1d21348 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -28,7 +28,7 @@ export class NotificationsCenter extends Themable { private static MAX_DIMENSIONS = new Dimension(450, 400); private readonly _onDidChangeVisibility: Emitter = this._register(new Emitter()); - get onDidChangeVisibility(): Event { return this._onDidChangeVisibility.event; } + readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; private notificationsCenterContainer: HTMLElement; private notificationsCenterHeader: HTMLElement; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index ad21cda900c..03fd18b705d 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -70,7 +70,7 @@ export class NotificationsList extends Themable { const renderer = this.instantiationService.createInstance(NotificationRenderer, actionRunner); // List - this.list = this._register(>this.instantiationService.createInstance( + this.list = this._register(this.instantiationService.createInstance( WorkbenchList, this.listContainer, new NotificationsListDelegate(this.listContainer), diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 506e6f876d7..1189df45c45 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/panelpart'; import { IAction } from 'vs/base/common/actions'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { IPanel, ActivePanelContext, PanelFocusContext } from 'vs/workbench/common/panel'; @@ -32,7 +32,6 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { isUndefinedOrNull, withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { LayoutPriority } from 'vs/base/browser/ui/grid/gridview'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; interface ICachedPanel { @@ -58,13 +57,25 @@ export class PanelPart extends CompositePart implements IPanelService { readonly minimumHeight: number = 77; readonly maximumHeight: number = Number.POSITIVE_INFINITY; - readonly snapSize: number = 50; - readonly priority: LayoutPriority = LayoutPriority.Low; + readonly snap = true; + + get preferredHeight(): number | undefined { + const sidebarDimension = this.layoutService.getDimension(Parts.SIDEBAR_PART); + return sidebarDimension.height * 0.4; + } + + get preferredWidth(): number | undefined { + const statusbarPart = this.layoutService.getDimension(Parts.STATUSBAR_PART); + return statusbarPart.width * 0.4; + } //#endregion get onDidPanelOpen(): Event<{ panel: IPanel, focus: boolean }> { return Event.map(this.onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus })); } - get onDidPanelClose(): Event { return this.onDidCompositeClose.event; } + readonly onDidPanelClose: Event = this.onDidCompositeClose.event; + + private _onDidVisibilityChange = this._register(new Emitter()); + readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; private activePanelContextKey: IContextKey; private panelFocusContextKey: IContextKey; @@ -73,7 +84,7 @@ export class PanelPart extends CompositePart implements IPanelService { private compositeActions: Map = new Map(); private blockOpeningPanel: boolean; - private dimension: Dimension; + private _contentDimension: Dimension; constructor( @INotificationService notificationService: INotificationService, @@ -292,21 +303,21 @@ export class PanelPart extends CompositePart implements IPanelService { } if (this.layoutService.getPanelPosition() === Position.RIGHT) { - this.dimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting + this._contentDimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting } else { - this.dimension = new Dimension(width, height!); + this._contentDimension = new Dimension(width, height!); } // Layout contents - super.layout(this.dimension.width, this.dimension.height); + super.layout(this._contentDimension.width, this._contentDimension.height); // Layout composite bar this.layoutCompositeBar(); } private layoutCompositeBar(): void { - if (this.dimension) { - let availableWidth = this.dimension.width - 40; // take padding into account + if (this._contentDimension) { + let availableWidth = this._contentDimension.width - 40; // take padding into account if (this.toolBar) { availableWidth = Math.max(PanelPart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.getToolbarWidth()); // adjust height for global actions showing } @@ -435,6 +446,10 @@ export class PanelPart extends CompositePart implements IPanelService { this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL); } + setVisible(visible: boolean): void { + this._onDidVisibilityChange.fire(visible); + } + toJSON(): object { return { type: Parts.PANEL_PART @@ -517,4 +532,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -registerSingleton(IPanelService, PanelPart); \ No newline at end of file +registerSingleton(IPanelService, PanelPart); diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index a1b09a2ea46..97bc546f7e8 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -252,7 +252,7 @@ export class QuickInputList { setRowLineHeight: false, multipleSelectionSupport: false, horizontalScrolling: false - } as IListOptions) as WorkbenchList; + } as IListOptions); this.list.getHTMLElement().id = id; this.disposables.push(this.list); this.disposables.push(this.list.onKeyDown(e => { diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 5851bdb62ce..f31bd9d480e 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -64,10 +64,10 @@ export class QuickOpenController extends Component implements IQuickOpenService _serviceBrand: ServiceIdentifier; private readonly _onShow: Emitter = this._register(new Emitter()); - get onShow(): Event { return this._onShow.event; } + readonly onShow: Event = this._onShow.event; private readonly _onHide: Emitter = this._register(new Emitter()); - get onHide(): Event { return this._onHide.event; } + readonly onHide: Event = this._onHide.event; private preserveInput: boolean; private isQuickOpen: boolean; @@ -745,7 +745,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { if (input instanceof EditorInput) { this.resource = resourceForEditorHistory(input, fileService); this.label = types.withNullAsUndefined(input.getName()); - this.description = types.withNullAsUndefined(input.getDescription()); + this.description = input.getDescription(); this.dirty = input.isDirty(); } else { const resourceInput = input as IResourceInput; diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index e8bc995e65a..8b50a07b662 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -30,7 +30,6 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { LayoutPriority } from 'vs/base/browser/ui/grid/gridview'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class SidebarPart extends CompositePart implements IViewletService { @@ -46,15 +45,33 @@ export class SidebarPart extends CompositePart implements IViewletServi readonly minimumHeight: number = 0; readonly maximumHeight: number = Number.POSITIVE_INFINITY; - readonly snapSize: number = 50; - readonly priority: LayoutPriority = LayoutPriority.Low; + readonly snap = true; + + get preferredWidth(): number | undefined { + const viewlet = this.getActiveViewlet(); + + if (!viewlet) { + return; + } + + const width = viewlet.getOptimalWidth(); + + if (typeof width !== 'number') { + return; + } + + return width; + } //#endregion get onDidViewletRegister(): Event { return >this.viewletRegistry.onDidRegister; } + private _onDidVisibilityChange = this._register(new Emitter()); + readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; + private _onDidViewletDeregister = this._register(new Emitter()); - get onDidViewletDeregister(): Event { return this._onDidViewletDeregister.event; } + readonly onDidViewletDeregister: Event = this._onDidViewletDeregister.event; get onDidViewletOpen(): Event { return Event.map(this.onDidCompositeOpen.event, compositeEvent => compositeEvent.composite); } get onDidViewletClose(): Event { return this.onDidCompositeClose.event as Event; } @@ -255,6 +272,10 @@ export class SidebarPart extends CompositePart implements IViewletServi } } + setVisible(visible: boolean): void { + this._onDidVisibilityChange.fire(visible); + } + toJSON(): object { return { type: Parts.SIDEBAR_PART @@ -298,4 +319,4 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(FocusSideBarAction, Fo primary: KeyMod.CtrlCmd | KeyCode.KEY_0 }), 'View: Focus into Side Bar', nls.localize('viewCategory', "View")); -registerSingleton(IViewletService, SidebarPart); \ No newline at end of file +registerSingleton(IViewletService, SidebarPart); diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 5c4e22b033c..ad1d1498654 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/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 00fe6c45bc4..089cbd3003e 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -611,6 +611,7 @@ export class StatusbarPart extends Part implements IStatusbarService { } layout(width: number, height: number): void { + super.layout(width, height); super.layoutContents(width, height); } @@ -816,4 +817,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -registerSingleton(IStatusbarService, StatusbarPart); \ No newline at end of file +registerSingleton(IStatusbarService, StatusbarPart); diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 83457d8a39f..f6b0a6849f9 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -56,7 +56,7 @@ export class TitlebarPart extends Part implements ITitleService { //#endregion private _onMenubarVisibilityChange = this._register(new Emitter()); - get onMenubarVisibilityChange(): Event { return this._onMenubarVisibilityChange.event; } + readonly onMenubarVisibilityChange: Event = this._onMenubarVisibilityChange.event; _serviceBrand: ServiceIdentifier; diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index ee1ae6612f9..53a104e4273 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -13,7 +13,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { ContextAwareMenuEntryActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IViewsService, ITreeView, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ViewContainer, ITreeItemLabel, Extensions } from 'vs/workbench/common/views'; +import { ITreeView, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ViewContainer, ITreeItemLabel, Extensions } from 'vs/workbench/common/views'; 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'; @@ -56,9 +56,9 @@ export class CustomTreeViewPanel extends ViewletPanel { @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, @IConfigurationService configurationService: IConfigurationService, - @IViewsService viewsService: IViewsService, + @IContextKeyService contextKeyService: IContextKeyService, ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService); const { treeView } = (Registry.as(Extensions.ViewsRegistry).getView(options.id)); this.treeView = treeView; this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this)); @@ -108,7 +108,7 @@ class TitleMenus extends Disposable { private titleSecondaryActions: IAction[] = []; private _onDidChangeTitle = this._register(new Emitter()); - get onDidChangeTitle(): Event { return this._onDidChangeTitle.event; } + readonly onDidChangeTitle: Event = this._onDidChangeTitle.event; constructor( id: string, @@ -385,13 +385,17 @@ export class CustomTreeView extends Disposable implements ITreeView { collapseByDefault: (e: ITreeItem): boolean => { return e.collapsibleState !== TreeItemCollapsibleState.Expanded; } - }) as WorkbenchAsyncDataTree); + })); aligner.tree = this.tree; this.tree.contextKeyService.createKey(this.id, true); this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e))); this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements))); this._register(this.tree.onDidChangeCollapseState(e => { + if (!e.node.element) { + return; + } + const element: ITreeItem = Array.isArray(e.node.element.element) ? e.node.element.element[0] : e.node.element.element; if (e.node.collapsed) { this._onDidCollapseItem.fire(element); diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts index 6c2671e227f..ef9dbe0d75f 100644 --- a/src/vs/workbench/browser/parts/views/panelViewlet.ts +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -26,8 +26,9 @@ import { PanelView, IPanelViewOptions, IPanelOptions, Panel } from 'vs/base/brow import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IView } from 'vs/workbench/common/views'; +import { IView, FocusedViewContext } from 'vs/workbench/common/views'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export interface IPanelColors extends IColorMapping { dropBackground?: ColorIdentifier; @@ -58,6 +59,8 @@ export abstract class ViewletPanel extends Panel implements IView { protected _onDidChangeTitleArea = this._register(new Emitter()); readonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event; + private focusedViewContextKey: IContextKey; + private _isVisible: boolean = false; readonly id: string; readonly title: string; @@ -71,13 +74,15 @@ export abstract class ViewletPanel extends Panel implements IView { options: IViewletPanelOptions, @IKeybindingService protected keybindingService: IKeybindingService, @IContextMenuService protected contextMenuService: IContextMenuService, - @IConfigurationService protected readonly configurationService: IConfigurationService + @IConfigurationService protected readonly configurationService: IConfigurationService, + @IContextKeyService contextKeyService: IContextKeyService ) { super(options); this.id = options.id; this.title = options.title; this.actionRunner = options.actionRunner; + this.focusedViewContextKey = FocusedViewContext.bindTo(contextKeyService); } setVisible(visible: boolean): void { @@ -112,8 +117,14 @@ export abstract class ViewletPanel extends Panel implements IView { const focusTracker = trackFocus(this.element); this._register(focusTracker); - this._register(focusTracker.onDidFocus(() => this._onDidFocus.fire())); - this._register(focusTracker.onDidBlur(() => this._onDidBlur.fire())); + this._register(focusTracker.onDidFocus(() => { + this.focusedViewContextKey.set(this.id); + this._onDidFocus.fire(); + })); + this._register(focusTracker.onDidBlur(() => { + this.focusedViewContextKey.reset(); + this._onDidBlur.fire(); + })); } protected renderHeader(container: HTMLElement): void { diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index ddf297c0264..ca709d3bd91 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -12,7 +12,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IContextKeyService, IContextKeyChangeEvent, IReadableSet, IContextKey, RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; import { sortedDiff, firstIndex, move, isNonEmptyArray } from 'vs/base/common/arrays'; -import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, isUndefined } from 'vs/base/common/types'; import { MenuId, MenuRegistry, ICommandAction } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { localize } from 'vs/nls'; @@ -205,9 +205,9 @@ class ViewDescriptorCollection extends Disposable implements IViewDescriptorColl } export interface IViewState { - visibleGlobal: boolean; - visibleWorkspace: boolean; - collapsed: boolean; + visibleGlobal: boolean | undefined; + visibleWorkspace: boolean | undefined; + collapsed: boolean | undefined; order?: number; size?: number; } @@ -238,6 +238,9 @@ export class ContributableViewsModel extends Disposable { private _onDidMove = this._register(new Emitter<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }>()); readonly onDidMove: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }> = this._onDidMove.event; + private _onDidChangeViewState = this._register(new Emitter()); + protected readonly onDidChangeViewState: Event = this._onDidChangeViewState.event; + constructor( container: ViewContainer, viewsService: IViewsService, @@ -284,7 +287,7 @@ export class ContributableViewsModel extends Disposable { } if (visible) { - this._onDidAdd.fire([{ index: visibleIndex, viewDescriptor, size: state.size, collapsed: state.collapsed }]); + this._onDidAdd.fire([{ index: visibleIndex, viewDescriptor, size: state.size, collapsed: !!state.collapsed }]); } else { this._onDidRemove.fire([{ index: visibleIndex, viewDescriptor }]); } @@ -297,12 +300,15 @@ export class ContributableViewsModel extends Disposable { throw new Error(`Unknown view ${id}`); } - return state.collapsed; + return !!state.collapsed; } setCollapsed(id: string, collapsed: boolean): void { - const { state } = this.find(id); - state.collapsed = collapsed; + const { index, state, viewDescriptor } = this.find(id); + if (state.collapsed !== collapsed) { + state.collapsed = collapsed; + this._onDidChangeViewState.fire({ viewDescriptor, index }); + } } getSize(id: string): number | undefined { @@ -316,8 +322,11 @@ export class ContributableViewsModel extends Disposable { } setSize(id: string, size: number): void { - const { state } = this.find(id); - state.size = size; + const { index, state, viewDescriptor } = this.find(id); + if (state.size !== size) { + state.size = size; + this._onDidChangeViewState.fire({ viewDescriptor, index }); + } } move(from: string, to: string): void { @@ -345,7 +354,7 @@ export class ContributableViewsModel extends Disposable { if (!viewState) { throw new Error(`Unknown view ${viewDescriptor.id}`); } - return viewDescriptor.workspace ? viewState.visibleWorkspace : viewState.visibleGlobal; + return viewDescriptor.workspace ? !!viewState.visibleWorkspace : !!viewState.visibleGlobal; } private find(id: string): { index: number, visibleIndex: number, viewDescriptor: IViewDescriptor, state: IViewState } { @@ -435,7 +444,7 @@ export class ContributableViewsModel extends Disposable { const state = this.viewStates.get(viewDescriptor.id)!; if (this.isViewDescriptorVisible(viewDescriptor)) { - toAdd.push({ index: startIndex++, viewDescriptor, size: state.size, collapsed: state.collapsed }); + toAdd.push({ index: startIndex++, viewDescriptor, size: state.size, collapsed: !!state.collapsed }); } } } @@ -452,10 +461,23 @@ export class ContributableViewsModel extends Disposable { } } +interface IStoredWorkspaceViewState { + collapsed: boolean; + isHidden: boolean; + size?: number; + order?: number; +} + +interface IStoredGlobalViewState { + id: string; + isHidden: boolean; + order?: number; +} + export class PersistentContributableViewsModel extends ContributableViewsModel { - private viewletStateStorageId: string; - private readonly hiddenViewsStorageId: string; + private readonly workspaceViewsStateStorageId: string; + private readonly globalViewsStateStorageId: string; private storageService: IStorageService; @@ -465,97 +487,124 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { @IViewsService viewsService: IViewsService, @IStorageService storageService: IStorageService, ) { - const hiddenViewsStorageId = `${viewletStateStorageId}.hidden`; - const viewStates = PersistentContributableViewsModel.loadViewsStates(viewletStateStorageId, hiddenViewsStorageId, storageService); + const globalViewsStateStorageId = `${viewletStateStorageId}.hidden`; + const viewStates = PersistentContributableViewsModel.loadViewsStates(viewletStateStorageId, globalViewsStateStorageId, storageService); super(container, viewsService, viewStates); - this.viewletStateStorageId = viewletStateStorageId; - this.hiddenViewsStorageId = hiddenViewsStorageId; + this.workspaceViewsStateStorageId = viewletStateStorageId; + this.globalViewsStateStorageId = globalViewsStateStorageId; this.storageService = storageService; - this._register(this.onDidAdd(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor)))); - this._register(this.onDidRemove(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor)))); - this._register(this.storageService.onWillSaveState(() => this.saveViewsStates())); + this._register(Event.any( + this.onDidAdd, + this.onDidRemove, + Event.map(this.onDidMove, ({ from, to }) => [from, to]), + Event.map(this.onDidChangeViewState, viewDescriptorRef => [viewDescriptorRef])) + (viewDescriptorRefs => this.saveViewsStates(viewDescriptorRefs.map(r => r.viewDescriptor)))); } - private saveViewsStates(): void { - const storedViewsStates: { [id: string]: { collapsed: boolean, size?: number, order?: number } } = {}; + private saveViewsStates(viewDescriptors: IViewDescriptor[]): void { + this.saveWorkspaceViewsStates(); + this.saveGlobalViewsStates(); + } + + private saveWorkspaceViewsStates(): void { + const storedViewsStates: { [id: string]: IStoredWorkspaceViewState } = {}; let hasState = false; for (const viewDescriptor of this.viewDescriptors) { const viewState = this.viewStates.get(viewDescriptor.id); if (viewState) { - storedViewsStates[viewDescriptor.id] = { collapsed: viewState.collapsed, size: viewState.size, order: viewState.order }; + storedViewsStates[viewDescriptor.id] = { + collapsed: !!viewState.collapsed, + isHidden: !viewState.visibleWorkspace, + size: viewState.size, + order: viewDescriptor.workspace && viewState ? viewState.order : undefined + }; hasState = true; } } if (hasState) { - this.storageService.store(this.viewletStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE); + this.storageService.store(this.workspaceViewsStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE); } else { - this.storageService.remove(this.viewletStateStorageId, StorageScope.WORKSPACE); + this.storageService.remove(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE); } } - private saveVisibilityStates(viewDescriptors: IViewDescriptor[]): void { - const globalViews: IViewDescriptor[] = viewDescriptors.filter(v => !v.workspace); - const workspaceViews: IViewDescriptor[] = viewDescriptors.filter(v => v.workspace); - if (globalViews.length) { - this.saveVisibilityStatesInScope(globalViews, StorageScope.GLOBAL); - } - if (workspaceViews.length) { - this.saveVisibilityStatesInScope(workspaceViews, StorageScope.WORKSPACE); + private saveGlobalViewsStates(): void { + const storedViewsVisibilityStates = PersistentContributableViewsModel.loadGlobalViewsState(this.globalViewsStateStorageId, this.storageService, StorageScope.GLOBAL); + for (const viewDescriptor of this.viewDescriptors) { + const viewState = this.viewStates.get(viewDescriptor.id); + storedViewsVisibilityStates.set(viewDescriptor.id, { + id: viewDescriptor.id, + isHidden: viewState && viewDescriptor.canToggleVisibility ? !viewState.visibleGlobal : false, + order: !viewDescriptor.workspace && viewState ? viewState.order : undefined + }); } + this.storageService.store(this.globalViewsStateStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL); } - private saveVisibilityStatesInScope(viewDescriptors: IViewDescriptor[], scope: StorageScope): void { - const storedViewsVisibilityStates = PersistentContributableViewsModel.loadViewsVisibilityState(this.hiddenViewsStorageId, this.storageService, scope); - for (const viewDescriptor of viewDescriptors) { - if (viewDescriptor.canToggleVisibility) { - const viewState = this.viewStates.get(viewDescriptor.id); - storedViewsVisibilityStates.set(viewDescriptor.id, { id: viewDescriptor.id, isHidden: viewState ? (scope === StorageScope.GLOBAL ? !viewState.visibleGlobal : !viewState.visibleWorkspace) : false }); - } - } - this.storageService.store(this.hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), scope); - } - private static loadViewsStates(viewletStateStorageId: string, hiddenViewsStorageId: string, storageService: IStorageService): Map { + private static loadViewsStates(workspaceViewsStateStorageId: string, globalViewsStateStorageId: string, storageService: IStorageService): Map { const viewStates = new Map(); - const storedViewsStates = JSON.parse(storageService.get(viewletStateStorageId, StorageScope.WORKSPACE, '{}')); - const globalVisibilityStates = this.loadViewsVisibilityState(hiddenViewsStorageId, storageService, StorageScope.GLOBAL); - const workspaceVisibilityStates = this.loadViewsVisibilityState(hiddenViewsStorageId, storageService, StorageScope.WORKSPACE); + const workspaceViewsStates = <{ [id: string]: IStoredWorkspaceViewState }>JSON.parse(storageService.get(workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}')); + for (const id of Object.keys(workspaceViewsStates)) { + const workspaceViewState = workspaceViewsStates[id]; + viewStates.set(id, { + visibleGlobal: undefined, + visibleWorkspace: isUndefined(workspaceViewState.isHidden) ? undefined : !workspaceViewState.isHidden, + collapsed: workspaceViewState.collapsed, + order: workspaceViewState.order + }); + } - for (const { id, isHidden } of values(globalVisibilityStates)) { - const viewState = storedViewsStates[id]; - if (viewState) { - viewStates.set(id, { ...viewState, ...{ visibleGlobal: !isHidden } }); - } else { - // New workspace - viewStates.set(id, { ...{ visibleGlobal: !isHidden } }); + // Migrate to `viewletStateStorageId` + const workspaceVisibilityStates = this.loadGlobalViewsState(globalViewsStateStorageId, storageService, StorageScope.WORKSPACE); + if (workspaceVisibilityStates.size > 0) { + for (const { id, isHidden } of values(workspaceVisibilityStates)) { + let viewState = viewStates.get(id); + // Not migrated to `viewletStateStorageId` + if (viewState) { + if (isUndefined(viewState.visibleWorkspace)) { + viewState.visibleWorkspace = !isHidden; + } + } else { + viewStates.set(id, { + collapsed: undefined, + visibleGlobal: undefined, + visibleWorkspace: !isHidden, + }); + } } + storageService.remove(globalViewsStateStorageId, StorageScope.WORKSPACE); } - for (const { id, isHidden } of values(workspaceVisibilityStates)) { - const viewState = storedViewsStates[id]; + + const globalViewsStates = this.loadGlobalViewsState(globalViewsStateStorageId, storageService, StorageScope.GLOBAL); + for (const { id, isHidden, order } of values(globalViewsStates)) { + let viewState = viewStates.get(id); if (viewState) { - viewStates.set(id, { ...viewState, ...{ visibleWorkspace: !isHidden } }); + viewState.visibleGlobal = !isHidden; + if (!isUndefined(order)) { + viewState.order = order; + } } else { - // New workspace - viewStates.set(id, { ...{ visibleWorkspace: !isHidden } }); - } - } - for (const id of Object.keys(storedViewsStates)) { - if (!viewStates.has(id)) { - viewStates.set(id, { ...storedViewsStates[id] }); + viewStates.set(id, { + visibleGlobal: !isHidden, + order, + collapsed: undefined, + visibleWorkspace: undefined, + }); } } return viewStates; } - private static loadViewsVisibilityState(hiddenViewsStorageId: string, storageService: IStorageService, scope: StorageScope): Map { - const storedVisibilityStates = >JSON.parse(storageService.get(hiddenViewsStorageId, scope, '[]')); + private static loadGlobalViewsState(globalViewsStateStorageId: string, storageService: IStorageService, scope: StorageScope): Map { + const storedValue = >JSON.parse(storageService.get(globalViewsStateStorageId, scope, '[]')); let hasDuplicates = false; - const storedViewsVisibilityStates = storedVisibilityStates.reduce((result, storedState) => { + const storedGlobalViewsState = storedValue.reduce((result, storedState) => { if (typeof storedState === 'string' /* migration */) { hasDuplicates = hasDuplicates || result.has(storedState); result.set(storedState, { id: storedState, isHidden: true }); @@ -564,13 +613,13 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { result.set(storedState.id, storedState); } return result; - }, new Map()); + }, new Map()); if (hasDuplicates) { - storageService.store(hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), scope); + storageService.store(globalViewsStateStorageId, JSON.stringify(values(storedGlobalViewsState)), scope); } - return storedViewsVisibilityStates; + return storedGlobalViewsState; } } @@ -725,4 +774,4 @@ export function createFileIconThemableTreeContainerScope(container: HTMLElement, return themeService.onDidFileIconThemeChange(onDidChangeFileIconTheme); } -registerSingleton(IViewsService, ViewsService); \ No newline at end of file +registerSingleton(IViewsService, ViewsService); diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 711c98c4755..3100093436c 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -263,13 +263,11 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView private toggleViewVisibility(viewId: string): void { const visible = !this.viewsModel.isVisible(viewId); - /* __GDPR__ - "views.toggleVisibility" : { - "viewId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "visible": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('views.toggledVisibility', { viewId, visible }); + type ViewsToggleVisibilityClassification = { + viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + visible: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ viewId: String, visible: boolean }, ViewsToggleVisibilityClassification>('views.toggleVisibility', { viewId, visible }); this.viewsModel.setVisible(viewId, visible); } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index d5f9cff6493..fadc5132cd2 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -20,7 +20,7 @@ import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remot import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IFileService, IFileSystemProvider } from 'vs/platform/files/common/files'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -40,6 +40,9 @@ import { joinPath } from 'vs/base/common/resources'; import { BrowserStorageService } from 'vs/platform/storage/browser/storageService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { RequestService } from 'vs/workbench/services/request/browser/requestService'; +import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider'; class CodeRendererMain extends Disposable { @@ -132,7 +135,7 @@ class CodeRendererMain extends Disposable { serviceCollection.set(ISignService, signService); // Remote Agent - const remoteAgentService = this._register(new RemoteAgentService(environmentService, productService, remoteAuthorityResolverService, signService)); + const remoteAgentService = this._register(new RemoteAgentService(this.configuration.webSocketFactory, environmentService, productService, remoteAuthorityResolverService, signService)); serviceCollection.set(IRemoteAgentService, remoteAgentService); // Files @@ -155,12 +158,14 @@ class CodeRendererMain extends Disposable { } } - // User Data Provider - if (userDataProvider) { - fileService.registerProvider(Schemas.userData, userDataProvider); + if (!userDataProvider) { + userDataProvider = this._register(new InMemoryUserDataProvider()); } - const services = await Promise.all([ + // User Data Provider + fileService.registerProvider(Schemas.userData, userDataProvider); + + const [configurationService, storageService] = await Promise.all([ this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => { // Workspace @@ -181,7 +186,10 @@ class CodeRendererMain extends Disposable { }) ]); - return { serviceCollection, logService, storageService: services[1] }; + // Request Service + serviceCollection.set(IRequestService, new RequestService(this.configuration.requestHandler, remoteAgentService, configurationService, logService)); + + return { serviceCollection, logService, storageService }; } private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise { diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 36fdab58002..3a5be568517 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -8,16 +8,11 @@ import * as browser from 'vs/base/browser/browser'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -// 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 { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IPager } from 'vs/base/common/paging'; -import { IExtensionManifest, 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 } from 'vs/platform/log/common/log'; +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'; import { IUpdateService, State } from 'vs/platform/update/common/update'; @@ -27,200 +22,21 @@ 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 -// 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'; 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 { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; - -//#region Clipboard - -export class SimpleClipboardService implements IClipboardService { - - _serviceBrand: any; - - writeText(text: string, type?: string): void { } - - readText(type?: string): string { - // @ts-ignore - return undefined; - } - - readTextSync(): string | undefined { - return undefined; - } - - readFindText(): string { - // @ts-ignore - return undefined; - } - - writeFindText(text: string): void { } - - writeResources(resources: URI[]): void { } - - readResources(): URI[] { - return []; - } - - hasResources(): boolean { - return false; - } -} - -registerSingleton(IClipboardService, SimpleClipboardService, true); - -//#endregion - -//#region Download - -export class SimpleDownloadService implements IDownloadService { - - _serviceBrand: any; - - download(uri: URI, to?: string, cancellationToken?: CancellationToken): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } -} - -registerSingleton(IDownloadService, SimpleDownloadService, true); - -//#endregion - -//#region Extension Gallery - -export class SimpleExtensionGalleryService implements IExtensionGalleryService { - - _serviceBrand: any; - - isEnabled(): boolean { - return false; - } - - query(token: CancellationToken): Promise>; - query(options: IQueryOptions, token: CancellationToken): Promise>; - query(arg1: any, arg2?: any): Promise> { - // @ts-ignore - return Promise.resolve(undefined); - } - - download(extension: IGalleryExtension, operation: InstallOperation): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise { - return Promise.resolve(undefined); - } - - getReadme(extension: IGalleryExtension, token: CancellationToken): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - getManifest(extension: IGalleryExtension, token: CancellationToken): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - getExtensionsReport(): Promise { - // @ts-ignore - return Promise.resolve(undefined); - } - - // @ts-ignore - getCompatibleExtension(extension: IGalleryExtension): Promise; - getCompatibleExtension(id: IExtensionIdentifier, version?: string): Promise; - getCompatibleExtension(id: any, version?: any) { - return Promise.resolve(undefined); - } -} - -registerSingleton(IExtensionGalleryService, SimpleExtensionGalleryService, 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 +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 Extension Tips @@ -253,7 +69,7 @@ export class SimpleExtensionTipsService implements IExtensionTipsService { } getAllIgnoredRecommendations(): { global: string[]; workspace: string[]; } { - return Object.create(null); + return { global: [], workspace: [] }; } } @@ -300,17 +116,17 @@ export class SimpleExtensionManagementService implements IExtensionManagementSer getInstalled(type?: ExtensionType): Promise { // @ts-ignore - return Promise.resolve(undefined); + return Promise.resolve([]); } getExtensionsReport(): Promise { // @ts-ignore - return Promise.resolve(undefined); + return Promise.resolve([]); } updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise { // @ts-ignore - return Promise.resolve(undefined); + return Promise.resolve(local); } } @@ -404,59 +220,6 @@ export class SimpleMultiExtensionsManagementService implements IExtensionManagem //#endregion -//#region Request - -export const IRequestService = createDecorator('requestService'); - -export interface IRequestService { - _serviceBrand: any; - - request(options: any, token: CancellationToken): Promise; -} - -export class SimpleRequestService implements IRequestService { - - _serviceBrand: any; - - request(options: any, token: CancellationToken): Promise { - return Promise.resolve(Object.create(null)); - } -} - -//#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 { @@ -529,7 +292,8 @@ export class SimpleWindowService extends Disposable implements IWindowService { @IFileService private readonly fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStorageService private readonly storageService: IStorageService, - @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService + @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, + @ILogService private readonly logService: ILogService ) { super(); @@ -657,7 +421,7 @@ export class SimpleWindowService extends Disposable implements IWindowService { async getRecentlyOpened(): Promise { const recentlyOpenedRaw = this.storageService.get(SimpleWindowService.RECENTLY_OPENED_KEY, StorageScope.GLOBAL); if (recentlyOpenedRaw) { - return restoreRecentlyOpened(JSON.parse(recentlyOpenedRaw)); + return restoreRecentlyOpened(JSON.parse(recentlyOpenedRaw), this.logService); } return { workspaces: [], files: [] }; @@ -797,23 +561,34 @@ 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, + //@IWindowService windowService: IWindowService, + @IEnvironmentService environmentService: IEnvironmentService + ) { + 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; + super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); - logToSession(sessionId: string, log: IRemoteConsoleLog): void { } - onLogToSession: Event = Event.None; - - terminateSession(sessionId: string, subId?: string): void { } - onTerminateSession: Event = Event.None; + this._register(this.onReload(event => { + if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) { + //windowService.reloadWindow(); + window.location.reload(); + } + })); + this._register(this.onClose(event => { + if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) { + //this._windowService.closeWindow(); + window.close(); + } + })); + } } registerSingleton(IExtensionHostDebugService, SimpleExtensionHostDebugService); @@ -958,6 +733,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(); } @@ -969,7 +791,7 @@ export class SimpleWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - log(_severity: string, ..._messages: string[]): Promise { + log(_severity: string, _args: string[]): Promise { return Promise.resolve(); } @@ -1126,3 +948,34 @@ class SimpleTunnelService implements ITunnelService { registerSingleton(ITunnelService, SimpleTunnelService); //#endregion + +//#region experiments + +class ExperimentService implements IExperimentService { + _serviceBrand: any; + + async getExperimentById(id: string): Promise { + return { + enabled: false, + id: '', + state: ExperimentState.NoRun + }; + } + + async getExperimentsByType(type: ExperimentActionType): Promise { + return []; + } + + async getCuratedExtensionsList(curatedExtensionsKey: string): Promise { + return []; + } + + markAsCompleted(experimentId: string): void { } + + onExperimentEnabled: Event = Event.None; + +} + +registerSingleton(IExperimentService, ExperimentService); + +//#endregion diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 664cc45a74e..54496ea933a 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -237,7 +237,7 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform' 'workbench.useExperimentalGridLayout': { 'type': 'boolean', 'description': nls.localize('workbench.useExperimentalGridLayout', "Enables the grid layout for the workbench. This setting may enable additional layout options for workbench components."), - 'default': false, + 'default': true, 'scope': ConfigurationScope.APPLICATION } } @@ -289,14 +289,14 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform' }, 'window.enableMenuBarMnemonics': { 'type': 'boolean', - 'default': true, + 'default': !isMacintosh, 'scope': ConfigurationScope.APPLICATION, 'description': nls.localize('enableMenuBarMnemonics', "Controls whether the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."), - 'included': isWindows || isLinux + 'included': isWindows || isLinux || isWeb }, 'window.customMenuBarAltFocus': { 'type': 'boolean', - 'default': true, + 'default': !isMacintosh, 'scope': ConfigurationScope.APPLICATION, 'markdownDescription': nls.localize('customMenuBarAltFocus', "Controls whether the menu bar will be focused by pressing the Alt-key. This setting has no effect on toggling the menu bar with the Alt-key."), 'included': isWindows || isLinux || isWeb diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index b7afc081ec7..634655ffa84 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -17,7 +17,7 @@ import { isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; -import { getServices } from 'vs/platform/instantiation/common/extensions'; +import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; import { Position, Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IStorageService, WillSaveStateReason, StorageScope, IWillSaveStateEvent } from 'vs/platform/storage/common/storage'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -48,10 +48,10 @@ import { Layout } from 'vs/workbench/browser/layout'; export class Workbench extends Layout { private readonly _onShutdown = this._register(new Emitter()); - get onShutdown(): Event { return this._onShutdown.event; } + readonly onShutdown: Event = this._onShutdown.event; private readonly _onWillShutdown = this._register(new Emitter()); - get onWillShutdown(): Event { return this._onWillShutdown.event; } + readonly onWillShutdown: Event = this._onWillShutdown.event; constructor( parent: HTMLElement, @@ -172,9 +172,9 @@ export class Workbench extends Layout { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // All Contributed Services - const contributedServices = getServices(); - for (let contributedService of contributedServices) { - serviceCollection.set(contributedService.id, contributedService.descriptor); + const contributedServices = getSingletonServiceDescriptors(); + for (let [id, descriptor] of contributedServices) { + serviceCollection.set(id, descriptor); } const instantiationService = new InstantiationService(serviceCollection, true); diff --git a/src/vs/workbench/buildfile.js b/src/vs/workbench/buildfile.js index 04e3814fa84..89939f33214 100644 --- a/src/vs/workbench/buildfile.js +++ b/src/vs/workbench/buildfile.js @@ -25,8 +25,8 @@ exports.collectModules = function () { createModuleDescription('vs/workbench/services/search/node/searchApp', []), - createModuleDescription('vs/workbench/services/files/node/watcher/unix/watcherApp', []), - createModuleDescription('vs/workbench/services/files/node/watcher/nsfw/watcherApp', []), + createModuleDescription('vs/platform/files/node/watcher/unix/watcherApp', []), + createModuleDescription('vs/platform/files/node/watcher/nsfw/watcherApp', []), createModuleDescription('vs/workbench/services/extensions/node/extensionHostProcess', []), ]; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 93dacfeacde..4cd3bb02e5d 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -295,7 +295,7 @@ export interface IEditorInput extends IDisposable { /** * Returns the display description of this input. */ - getDescription(verbosity?: Verbosity): string | null; + getDescription(verbosity?: Verbosity): string | undefined; /** * Returns the display title of this input. @@ -330,13 +330,13 @@ export interface IEditorInput extends IDisposable { export abstract class EditorInput extends Disposable implements IEditorInput { protected readonly _onDidChangeDirty: Emitter = this._register(new Emitter()); - get onDidChangeDirty(): Event { return this._onDidChangeDirty.event; } + readonly onDidChangeDirty: Event = this._onDidChangeDirty.event; protected readonly _onDidChangeLabel: Emitter = this._register(new Emitter()); - get onDidChangeLabel(): Event { return this._onDidChangeLabel.event; } + readonly onDidChangeLabel: Event = this._onDidChangeLabel.event; private readonly _onDispose: Emitter = this._register(new Emitter()); - get onDispose(): Event { return this._onDispose.event; } + readonly onDispose: Event = this._onDispose.event; private disposed: boolean = false; @@ -364,8 +364,8 @@ export abstract class EditorInput extends Disposable implements IEditorInput { * Returns the description of this input that can be shown to the user. Examples include showing the description of * the input above the editor area to the side of the name of the input. */ - getDescription(verbosity?: Verbosity): string | null { - return null; + getDescription(verbosity?: Verbosity): string | undefined { + return undefined; } /** @@ -380,12 +380,12 @@ export abstract class EditorInput extends Disposable implements IEditorInput { * Returns the preferred editor for this input. A list of candidate editors is passed in that whee registered * for the input. This allows subclasses to decide late which editor to use for the input on a case by case basis. */ - getPreferredEditorId(candidates: string[]): string | null { - if (candidates && candidates.length > 0) { + getPreferredEditorId(candidates: string[]): string | undefined { + if (candidates.length > 0) { return candidates[0]; } - return null; + return undefined; } /** @@ -552,7 +552,7 @@ export class SideBySideEditorInput extends EditorInput { constructor( private readonly name: string, - private readonly description: string | null, + private readonly description: string | undefined, private readonly _details: EditorInput, private readonly _master: EditorInput ) { @@ -625,7 +625,7 @@ export class SideBySideEditorInput extends EditorInput { return this.name; } - getDescription(): string | null { + getDescription(): string | undefined { return this.description; } @@ -658,7 +658,7 @@ export interface ITextEditorModel extends IEditorModel { export class EditorModel extends Disposable implements IEditorModel { private readonly _onDispose: Emitter = this._register(new Emitter()); - get onDispose(): Event { return this._onDispose.event; } + readonly onDispose: Event = this._onDispose.event; /** * Causes this model to load returning a promise when loading is completed. diff --git a/src/vs/workbench/common/editor/dataUriEditorInput.ts b/src/vs/workbench/common/editor/dataUriEditorInput.ts index 7c82702e21c..f75c3d04103 100644 --- a/src/vs/workbench/common/editor/dataUriEditorInput.ts +++ b/src/vs/workbench/common/editor/dataUriEditorInput.ts @@ -55,8 +55,8 @@ export class DataUriEditorInput extends EditorInput { return withUndefinedAsNull(this.name); } - getDescription(): string | null { - return withUndefinedAsNull(this.description); + getDescription(): string | undefined { + return this.description; } resolve(): Promise { diff --git a/src/vs/workbench/common/editor/diffEditorInput.ts b/src/vs/workbench/common/editor/diffEditorInput.ts index bd4aea9a15b..477d54e754c 100644 --- a/src/vs/workbench/common/editor/diffEditorInput.ts +++ b/src/vs/workbench/common/editor/diffEditorInput.ts @@ -18,7 +18,7 @@ export class DiffEditorInput extends SideBySideEditorInput { private cachedModel: DiffEditorModel | null; - constructor(name: string, description: string | null, original: EditorInput, modified: EditorInput, private readonly forceOpenAsBinary?: boolean) { + constructor(name: string, description: string | undefined, original: EditorInput, modified: EditorInput, private readonly forceOpenAsBinary?: boolean) { super(name, description, original, modified); } diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index 7d4ca0c5e52..5b207d4a79d 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -60,31 +60,31 @@ export class EditorGroup extends Disposable { //#region events private readonly _onDidEditorActivate = this._register(new Emitter()); - get onDidEditorActivate(): Event { return this._onDidEditorActivate.event; } + readonly onDidEditorActivate: Event = this._onDidEditorActivate.event; private readonly _onDidEditorOpen = this._register(new Emitter()); - get onDidEditorOpen(): Event { return this._onDidEditorOpen.event; } + readonly onDidEditorOpen: Event = this._onDidEditorOpen.event; private readonly _onDidEditorClose = this._register(new Emitter()); - get onDidEditorClose(): Event { return this._onDidEditorClose.event; } + readonly onDidEditorClose: Event = this._onDidEditorClose.event; private readonly _onDidEditorDispose = this._register(new Emitter()); - get onDidEditorDispose(): Event { return this._onDidEditorDispose.event; } + readonly onDidEditorDispose: Event = this._onDidEditorDispose.event; private readonly _onDidEditorBecomeDirty = this._register(new Emitter()); - get onDidEditorBecomeDirty(): Event { return this._onDidEditorBecomeDirty.event; } + readonly onDidEditorBecomeDirty: Event = this._onDidEditorBecomeDirty.event; private readonly _onDidEditorLabelChange = this._register(new Emitter()); - get onDidEditorLabelChange(): Event { return this._onDidEditorLabelChange.event; } + readonly onDidEditorLabelChange: Event = this._onDidEditorLabelChange.event; private readonly _onDidEditorMove = this._register(new Emitter()); - get onDidEditorMove(): Event { return this._onDidEditorMove.event; } + readonly onDidEditorMove: Event = this._onDidEditorMove.event; private readonly _onDidEditorPin = this._register(new Emitter()); - get onDidEditorPin(): Event { return this._onDidEditorPin.event; } + readonly onDidEditorPin: Event = this._onDidEditorPin.event; private readonly _onDidEditorUnpin = this._register(new Emitter()); - get onDidEditorUnpin(): Event { return this._onDidEditorUnpin.event; } + readonly onDidEditorUnpin: Event = this._onDidEditorUnpin.event; //#endregion @@ -138,16 +138,16 @@ export class EditorGroup extends Disposable { return mru ? this.mru.slice(0) : this.editors.slice(0); } - getEditor(index: number): EditorInput | null; - getEditor(resource: URI): EditorInput | null; - getEditor(arg1: number | URI): EditorInput | null { + getEditor(index: number): EditorInput | undefined; + getEditor(resource: URI): EditorInput | undefined; + getEditor(arg1: number | URI): EditorInput | undefined { if (typeof arg1 === 'number') { return this.editors[arg1]; } const resource: URI = arg1; if (!this.contains(resource)) { - return null; // fast check for resource opened or not + return undefined; // fast check for resource opened or not } for (const editor of this.editors) { @@ -157,7 +157,7 @@ export class EditorGroup extends Disposable { } } - return null; + return undefined; } get activeEditor(): EditorInput | null { diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 6d652b4e8ca..8ea157dffc2 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -22,7 +22,7 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { constructor( private name: string, - private description: string | null, + private description: string | undefined, private readonly resource: URI, private preferredMode: string | undefined, @ITextModelService private readonly textModelResolverService: ITextModelService @@ -53,7 +53,7 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { } } - getDescription(): string | null { + getDescription(): string | undefined { return this.description; } diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 16f96244129..561b5cb6f87 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -28,10 +28,10 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport private modelResolve: Promise | null; private readonly _onDidModelChangeContent: Emitter = this._register(new Emitter()); - get onDidModelChangeContent(): Event { return this._onDidModelChangeContent.event; } + readonly onDidModelChangeContent: Event = this._onDidModelChangeContent.event; private readonly _onDidModelChangeEncoding: Emitter = this._register(new Emitter()); - get onDidModelChangeEncoding(): Event { return this._onDidModelChangeEncoding.event; } + readonly onDidModelChangeEncoding: Event = this._onDidModelChangeEncoding.event; constructor( private readonly resource: URI, @@ -77,9 +77,9 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.labelService.getUriLabel(dirname(this.resource)); } - getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string | null { + getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string | undefined { if (!this.hasAssociatedFilePath) { - return null; + return undefined; } switch (verbosity) { diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 8b2c38d28f6..57a77b7267b 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -22,13 +22,13 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY; private readonly _onDidChangeContent: Emitter = this._register(new Emitter()); - get onDidChangeContent(): Event { return this._onDidChangeContent.event; } + readonly onDidChangeContent: Event = this._onDidChangeContent.event; private readonly _onDidChangeDirty: Emitter = this._register(new Emitter()); - get onDidChangeDirty(): Event { return this._onDidChangeDirty.event; } + readonly onDidChangeDirty: Event = this._onDidChangeDirty.event; private readonly _onDidChangeEncoding: Emitter = this._register(new Emitter()); - get onDidChangeEncoding(): Event { return this._onDidChangeEncoding.event; } + readonly onDidChangeEncoding: Event = this._onDidChangeEncoding.event; private dirty: boolean = false; private versionId: number = 0; diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index e4718e06f67..b83f9599436 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -86,7 +86,7 @@ export interface IStatusMessageChangeEvent { export class NotificationHandle implements INotificationHandle { private readonly _onDidClose: Emitter = new Emitter(); - get onDidClose(): Event { return this._onDidClose.event; } + readonly onDidClose: Event = this._onDidClose.event; constructor(private readonly item: INotificationViewItem, private readonly closeItem: (item: INotificationViewItem) => void) { this.registerListeners(); @@ -126,10 +126,10 @@ export class NotificationsModel extends Disposable implements INotificationsMode private static NO_OP_NOTIFICATION = new NoOpNotification(); private readonly _onDidNotificationChange: Emitter = this._register(new Emitter()); - get onDidNotificationChange(): Event { return this._onDidNotificationChange.event; } + readonly onDidNotificationChange: Event = this._onDidNotificationChange.event; private readonly _onDidStatusMessageChange: Emitter = this._register(new Emitter()); - get onDidStatusMessageChange(): Event { return this._onDidStatusMessageChange.event; } + readonly onDidStatusMessageChange: Event = this._onDidStatusMessageChange.event; private readonly _notifications: INotificationViewItem[] = []; get notifications(): INotificationViewItem[] { return this._notifications; } @@ -301,7 +301,7 @@ export class NotificationViewItemProgress extends Disposable implements INotific private readonly _state: INotificationViewItemProgressState; private readonly _onDidChange: Emitter = this._register(new Emitter()); - get onDidChange(): Event { return this._onDidChange.event; } + readonly onDidChange: Event = this._onDidChange.event; constructor() { super(); @@ -397,13 +397,13 @@ export class NotificationViewItem extends Disposable implements INotificationVie private _progress: NotificationViewItemProgress; private readonly _onDidExpansionChange: Emitter = this._register(new Emitter()); - get onDidExpansionChange(): Event { return this._onDidExpansionChange.event; } + readonly onDidExpansionChange: Event = this._onDidExpansionChange.event; private readonly _onDidClose: Emitter = this._register(new Emitter()); - get onDidClose(): Event { return this._onDidClose.event; } + readonly onDidClose: Event = this._onDidClose.event; private readonly _onDidLabelChange: Emitter = this._register(new Emitter()); - get onDidLabelChange(): Event { return this._onDidLabelChange.event; } + readonly onDidLabelChange: Event = this._onDidLabelChange.event; static create(notification: INotification): INotificationViewItem | null { if (!notification || !notification.message || isPromiseCanceledError(notification.message)) { @@ -654,7 +654,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie export class ChoiceAction extends Action { private readonly _onDidRun = new Emitter(); - get onDidRun(): Event { return this._onDidRun.event; } + readonly onDidRun: Event = this._onDidRun.event; private readonly _keepOpen: boolean; diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 1b1e64b5992..53de865d8f1 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -107,7 +107,7 @@ export class ResourceGlobMatcher extends Disposable { private static readonly NO_ROOT: string | null = null; private readonly _onExpressionChange: Emitter = this._register(new Emitter()); - get onExpressionChange(): Event { return this._onExpressionChange.event; } + readonly onExpressionChange: Event = this._onExpressionChange.event; private readonly mapRootToParsedExpression: Map = new Map(); private readonly mapRootToExpressionConfig: Map = new Map(); diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 51139cefce6..6f5386ee4a8 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -6,7 +6,7 @@ import { Command } from 'vs/editor/common/modes'; import { UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ITreeViewDataProvider } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; import { IViewlet } from 'vs/workbench/common/viewlet'; @@ -21,6 +21,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test'; +export const FocusedViewContext = new RawContextKey('focusedView', ''); export namespace Extensions { export const ViewContainersRegistry = 'workbench.registry.view.containers'; diff --git a/src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg b/src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg deleted file mode 100644 index 21058f74e72..00000000000 --- a/src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index b949e001a30..5fac853caaa 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -9,7 +9,7 @@ import { Widget } from 'vs/base/browser/ui/widget'; import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { mixin } from 'vs/base/common/objects'; import { isMacintosh } from 'vs/base/common/platform'; import { URI as uri } from 'vs/base/common/uri'; @@ -103,7 +103,6 @@ export class SuggestEnabledInput extends Widget implements IThemable { private _onInputDidChange = new Emitter(); readonly onInputDidChange: Event = this._onInputDidChange.event; - private disposables: IDisposable[] = []; private readonly inputWidget: CodeEditorWidget; private readonly inputModel: ITextModel; private stylingContainer: HTMLDivElement; @@ -134,31 +133,31 @@ export class SuggestEnabledInput extends Widget implements IThemable { contributions: [SuggestController, SnippetController2, ContextMenuController, MenuPreventer, SelectionClipboard], isSimpleWidget: true, }); - this.disposables.push(this.inputWidget); + this._register(this.inputWidget); let scopeHandle = uri.parse(resourceHandle); this.inputModel = modelService.createModel('', null, scopeHandle, true); this.inputWidget.setModel(this.inputModel); - this.disposables.push(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses + this._register(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses - this.disposables.push((this.inputWidget.onDidFocusEditorText(() => { + this._register((this.inputWidget.onDidFocusEditorText(() => { if (options.focusContextKey) { options.focusContextKey.set(true); } addClass(this.stylingContainer, 'synthetic-focus'); }))); - this.disposables.push((this.inputWidget.onDidBlurEditorText(() => { + this._register((this.inputWidget.onDidBlurEditorText(() => { if (options.focusContextKey) { options.focusContextKey.set(false); } removeClass(this.stylingContainer, 'synthetic-focus'); }))); const onKeyDownMonaco = Event.chain(this.inputWidget.onKeyDown); - onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this, this.disposables); - onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this, this.disposables); + this._register(onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this)); + this._register(onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this)); let preexistingContent = this.getValue(); const inputWidgetModel = this.inputWidget.getModel(); if (inputWidgetModel) { - this.disposables.push(inputWidgetModel.onDidChangeContent(() => { + this._register(inputWidgetModel.onDidChangeContent(() => { let content = this.getValue(); this.placeholderText.style.visibility = content ? 'hidden' : 'visible'; if (preexistingContent.trim() === content.trim()) { return; } @@ -175,7 +174,7 @@ export class SuggestEnabledInput extends Widget implements IThemable { this.setValue(options.value || ''); - this.disposables.push(modes.CompletionProviderRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, { + this._register(modes.CompletionProviderRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, { triggerCharacters: validatedSuggestProvider.triggerCharacters, provideCompletionItems: (model: ITextModel, position: Position, _context: modes.CompletionContext) => { let query = model.getValue(); @@ -249,11 +248,6 @@ export class SuggestEnabledInput extends Widget implements IThemable { private selectAll(): void { this.inputWidget.setSelection(new Range(1, 1, 1, this.getValue().length + 1)); } - - dispose(): void { - this.disposables = dispose(this.disposables); - super.dispose(); - } } // Override styles in selections.ts diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index d2a7bd7f4c0..eb15bf10a1f 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -18,6 +18,7 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { DefaultSettingsEditorContribution } from 'vs/workbench/contrib/preferences/browser/preferencesEditor'; const transientWordWrapState = 'transientWordWrapState'; const isWordWrapMinifiedKey = 'isWordWrapMinified'; @@ -131,6 +132,10 @@ class ToggleWordWrapAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + if (editor.getContribution(DefaultSettingsEditorContribution.ID)) { + // in the settings editor... + return; + } if (!editor.hasModel()) { return; } @@ -201,6 +206,10 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution })); const ensureWordWrapSettings = () => { + if (this.editor.getContribution(DefaultSettingsEditorContribution.ID)) { + // in the settings editor... + return; + } // Ensure correct word wrap settings const newModel = this.editor.getModel(); if (!newModel) { @@ -267,7 +276,7 @@ function canToggleWordWrap(uri: URI): boolean { if (!uri) { return false; } - return (uri.scheme !== 'output' && uri.scheme !== 'vscode'); + return (uri.scheme !== 'output'); } @@ -279,7 +288,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_WORD_WRAP_ID, title: nls.localize('unwrapMinified', "Disable wrapping for this file"), - iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg')) } + iconLocation: { + dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), + light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + } }, group: 'navigation', order: 1, @@ -293,7 +305,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_WORD_WRAP_ID, title: nls.localize('wrapMinified', "Enable wrapping for this file"), - iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg')) } + iconLocation: { + dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), + light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + } }, group: 'navigation', order: 1, diff --git a/src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg new file mode 100644 index 00000000000..f54d621127f --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg new file mode 100644 index 00000000000..6a8e3fdf933 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 0b6b347c978..e8d7d850123 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -28,7 +28,7 @@ import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; -import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { MenuItemAction, SubmenuItemAction, IMenu } from 'vs/platform/actions/common/actions'; import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -54,7 +54,7 @@ export class CommentNode extends Disposable { private _commentContextValue: IContextKey; protected actionRunner?: IActionRunner; - protected toolbar: ToolBar; + protected toolbar: ToolBar | undefined; private _commentFormActions: CommentFormActions; private _onDidDelete = new Emitter(); @@ -134,14 +134,54 @@ export class CommentNode extends Disposable { this.createActionsToolbar(); } + private getToolbarActions(menu: IMenu): { primary: IAction[], secondary: IAction[] } { + const contributedActions = menu.getActions({ shouldForwardArgs: true }); + const primary: IAction[] = []; + const secondary: IAction[] = []; + const result = { primary, secondary }; + fillInActions(contributedActions, result, false, g => /^inline/.test(g)); + return result; + } + + private createToolbar() { + this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { + actionViewItemProvider: action => { + if (action.id === ToggleReactionsAction.ID) { + return new DropdownMenuActionViewItem( + action, + (action).menuActions, + this.contextMenuService, + action => { + return this.actionViewItemProvider(action as Action); + }, + this.actionRunner!, + undefined, + 'toolbar-toggle-pickReactions', + () => { return AnchorAlignment.RIGHT; } + ); + } + return this.actionViewItemProvider(action as Action); + }, + orientation: ActionsOrientation.HORIZONTAL + }); + + this.toolbar.context = { + thread: this.commentThread, + commentUniqueId: this.comment.uniqueIdInThread, + $mid: 9 + }; + + this.registerActionBarListeners(this._actionsToolbarContainer); + this._register(this.toolbar); + } + private createActionsToolbar() { const actions: IAction[] = []; - const secondaryActions: IAction[] = []; let hasReactionHandler = this.commentService.hasReactionHandler(this.owner); if (hasReactionHandler) { - let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); + let toggleReactionAction = this.createReactionPicker(this.comment.commentReactions || []); actions.push(toggleReactionAction); } @@ -149,60 +189,26 @@ export class CommentNode extends Disposable { const menu = commentMenus.getCommentTitleActions(this.comment, this._contextKeyService); this._register(menu); this._register(menu.onDidChange(e => { - const primary: IAction[] = []; - const secondary: IAction[] = []; - const result = { primary, secondary }; - fillInActions(contributedActions, result, false, g => /^inline/.test(g)); - this.toolbar.setActions(primary, secondary); + const { primary, secondary } = this.getToolbarActions(menu); + if (!this.toolbar && (primary.length || secondary.length)) { + this.createToolbar(); + } + + this.toolbar!.setActions(primary, secondary)(); })); - const contributedActions = menu.getActions({ shouldForwardArgs: true }); - { - const primary: IAction[] = []; - const secondary: IAction[] = []; - const result = { primary, secondary }; - fillInActions(contributedActions, result, false, g => /^inline/.test(g)); - actions.push(...primary); - secondaryActions.push(...secondary); - } + const { primary, secondary } = this.getToolbarActions(menu); + actions.push(...primary); - if (actions.length) { - this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { - actionViewItemProvider: action => { - if (action.id === ToggleReactionsAction.ID) { - return new DropdownMenuActionViewItem( - action, - (action).menuActions, - this.contextMenuService, - action => { - return this.actionViewItemProvider(action as Action); - }, - this.actionRunner!, - undefined, - 'toolbar-toggle-pickReactions', - () => { return AnchorAlignment.RIGHT; } - ); - } - return this.actionViewItemProvider(action as Action); - }, - orientation: ActionsOrientation.HORIZONTAL - }); - - this.toolbar.context = { - thread: this.commentThread, - commentUniqueId: this.comment.uniqueIdInThread, - $mid: 9 - }; - - this.registerActionBarListeners(this._actionsToolbarContainer); - this.toolbar.setActions(actions, secondaryActions)(); - this._register(this.toolbar); + if (actions.length || secondary.length) { + this.createToolbar(); + this.toolbar!.setActions(actions, secondary)(); } } actionViewItemProvider(action: Action) { let options = {}; - if (action.id === 'comment.delete' || action.id === 'comment.edit' || action.id === ToggleReactionsAction.ID) { + if (action.id === ToggleReactionsAction.ID) { options = { label: false, icon: true }; } else { options = { label: false, icon: true }; @@ -220,7 +226,7 @@ export class CommentNode extends Disposable { } } - private createReactionPicker2(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction { + private createReactionPicker(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction { let toggleReactionActionViewItem: DropdownMenuActionViewItem; let toggleReactionAction = this._register(new ToggleReactionsAction(() => { if (toggleReactionActionViewItem) { @@ -315,21 +321,15 @@ export class CommentNode extends Disposable { }); if (hasReactionHandler) { - let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); + let toggleReactionAction = this.createReactionPicker(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 }); - } } } 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); @@ -520,4 +520,4 @@ function fillInActions(groups: [string, Array; 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 67f7d8f2042..0bd28e5fe58 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -115,7 +115,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._contextKeyService = contextKeyService.createScoped(this.domNode); this._threadIsEmpty = CommentContextKeys.commentThreadIsEmpty.bindTo(this._contextKeyService); this._threadIsEmpty.set(!_commentThread.comments || !_commentThread.comments.length); - this._commentThreadContextValue = contextKeyService.createKey('commentThread', _commentThread.contextValue); + this._commentThreadContextValue = this._contextKeyService.createKey('commentThread', _commentThread.contextValue); this._resizeObserver = null; this._isExpanded = _commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded; @@ -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,9 +309,8 @@ 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; newCommentNodeList.unshift(oldCommentNode[0]); } else { @@ -601,13 +605,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); } @@ -893,4 +897,4 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._submitActionsDisposables.forEach(local => local.dispose()); this._onDidClose.fire(undefined); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 35d61c27f4b..89dd182ebe2 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 dd9a18a0ff7..27440e3e996 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 fb60a911d6d..090ffa54650 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -20,10 +20,10 @@ export class CommentsDataSource implements IDataSource { return 'root'; } if (element instanceof ResourceWithCommentThreads) { - return element.id; + return `${element.owner}-${element.id}`; } if (element instanceof CommentNode) { - return `${element.resource.toString()}-${element.comment.commentId}`; + return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}` + (element.isRoot ? '-root' : ''); } 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 75644595d19..00000000000 --- 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 75644595d19..00000000000 --- 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 cf5f28ca35c..00000000000 --- 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 a72757482be..00000000000 --- 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 b507253e449..00000000000 --- 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 ae71150c0c8..00000000000 --- 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 82ad6c76234..47f8feb5fc9 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,9 @@ height: 100%; } -.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-item { +.monaco-editor .review-widget .action-item { + min-width: 18px; + min-height: 20px; margin-left: 4px; } diff --git a/src/vs/workbench/contrib/comments/common/commentModel.ts b/src/vs/workbench/contrib/comments/common/commentModel.ts index d2a03f5ccd5..256b3dda7e6 100644 --- a/src/vs/workbench/contrib/comments/common/commentModel.ts +++ b/src/vs/workbench/contrib/comments/common/commentModel.ts @@ -15,17 +15,21 @@ export interface ICommentThreadChangedEvent extends CommentThreadChangedEvent { } export class CommentNode { + owner: string; threadId: string; range: IRange; comment: Comment; replies: CommentNode[] = []; resource: URI; + isRoot: boolean; - constructor(threadId: string, resource: URI, comment: Comment, range: IRange) { + constructor(owner: string, threadId: string, resource: URI, comment: Comment, range: IRange) { + this.owner = owner; this.threadId = threadId; this.comment = comment; this.resource = resource; this.range = range; + this.isRoot = false; } hasReply(): boolean { @@ -35,22 +39,26 @@ export class CommentNode { export class ResourceWithCommentThreads { id: string; + owner: string; commentThreads: CommentNode[]; // The top level comments on the file. Replys are nested under each node. resource: URI; - constructor(resource: URI, commentThreads: CommentThread[]) { + constructor(owner: string, resource: URI, commentThreads: CommentThread[]) { + this.owner = owner; this.id = resource.toString(); this.resource = resource; - this.commentThreads = commentThreads.filter(thread => thread.comments && thread.comments.length).map(thread => ResourceWithCommentThreads.createCommentNode(resource, thread)); + this.commentThreads = commentThreads.filter(thread => thread.comments && thread.comments.length).map(thread => ResourceWithCommentThreads.createCommentNode(owner, resource, thread)); } - public static createCommentNode(resource: URI, commentThread: CommentThread): CommentNode { + public static createCommentNode(owner: string, resource: URI, commentThread: CommentThread): CommentNode { const { threadId, comments, range } = commentThread; - const commentNodes: CommentNode[] = comments!.map(comment => new CommentNode(threadId!, resource, comment, range)); + const commentNodes: CommentNode[] = comments!.map(comment => new CommentNode(owner, threadId!, resource, comment, range)); if (commentNodes.length > 1) { commentNodes[0].replies = commentNodes.slice(1, commentNodes.length); } + commentNodes[0].isRoot = true; + return commentNodes[0]; } } @@ -65,7 +73,7 @@ export class CommentsModel { } public setCommentThreads(owner: string, commentThreads: CommentThread[]): void { - this.commentThreadsMap.set(owner, this.groupByResource(commentThreads)); + this.commentThreadsMap.set(owner, this.groupByResource(owner, commentThreads)); this.resourceCommentThreads = flatten(values(this.commentThreadsMap)); } @@ -97,9 +105,9 @@ export class CommentsModel { // Find comment node on resource that is that thread and replace it const index = firstIndex(matchingResourceData.commentThreads, (commentThread) => commentThread.threadId === thread.threadId); if (index >= 0) { - matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread); + matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(owner, URI.parse(matchingResourceData.id), thread); } else if (thread.comments && thread.comments.length) { - matchingResourceData.commentThreads.push(ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread)); + matchingResourceData.commentThreads.push(ResourceWithCommentThreads.createCommentNode(owner, URI.parse(matchingResourceData.id), thread)); } }); @@ -108,10 +116,10 @@ export class CommentsModel { if (existingResource.length) { const resource = existingResource[0]; if (thread.comments && thread.comments.length) { - resource.commentThreads.push(ResourceWithCommentThreads.createCommentNode(resource.resource, thread)); + resource.commentThreads.push(ResourceWithCommentThreads.createCommentNode(owner, resource.resource, thread)); } } else { - threadsForOwner.push(new ResourceWithCommentThreads(URI.parse(thread.resource!), [thread])); + threadsForOwner.push(new ResourceWithCommentThreads(owner, URI.parse(thread.resource!), [thread])); } }); @@ -133,11 +141,11 @@ export class CommentsModel { } } - private groupByResource(commentThreads: CommentThread[]): ResourceWithCommentThreads[] { + private groupByResource(owner: string, commentThreads: CommentThread[]): ResourceWithCommentThreads[] { const resourceCommentThreads: ResourceWithCommentThreads[] = []; const commentThreadsByResource = new Map(); for (const group of groupBy(commentThreads, CommentsModel._compareURIs)) { - commentThreadsByResource.set(group[0].resource!, new ResourceWithCommentThreads(URI.parse(group[0].resource!), group)); + commentThreadsByResource.set(group[0].resource!, new ResourceWithCommentThreads(owner, URI.parse(group[0].resource!), group)); } commentThreadsByResource.forEach((v, i, m) => { diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index e0fa0e6c9f3..87094b93ebc 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -30,6 +30,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { ILabelService } from 'vs/platform/label/common/label'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const $ = dom.$; @@ -56,9 +57,10 @@ export class BreakpointsView extends ViewletPanel { @IThemeService private readonly themeService: IThemeService, @IEditorService private readonly editorService: IEditorService, @IContextViewService private readonly contextViewService: IContextViewService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IContextKeyService contextKeyService: IContextKeyService, ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(); this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange())); @@ -83,7 +85,7 @@ export class BreakpointsView extends ViewletPanel { getRole: (breakpoint: IEnablement) => 'checkbox', isChecked: (breakpoint: IEnablement) => breakpoint.enabled } - }) as WorkbenchList; + }); CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService); diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 6d94222b5b8..142460a504c 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -60,7 +60,7 @@ export class CallStackView extends ViewletPanel { @IMenuService menuService: IMenuService, @IContextKeyService readonly contextKeyService: IContextKeyService, ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('callstackSection', "Call Stack Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('callstackSection', "Call Stack Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); this.callStackItemType = CONTEXT_CALLSTACK_ITEM_TYPE.bindTo(contextKeyService); this.contributedContextMenu = menuService.createMenu(MenuId.DebugCallStackContext, contextKeyService); @@ -145,7 +145,7 @@ export class CallStackView extends ViewletPanel { return nls.localize('showMoreStackFrames2', "Show More Stack Frames"); } } - }) as WorkbenchAsyncDataTree; + }); this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError); diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 84afaa1d2f1..9a1431da67e 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -534,7 +534,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, { // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr, icon: string) => { + const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, icon: string) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, diff --git a/src/vs/workbench/contrib/debug/browser/debugActions.ts b/src/vs/workbench/contrib/debug/browser/debugActions.ts index 0f16da0f89f..f2ed8a479ac 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActions.ts @@ -398,11 +398,11 @@ export class CopyValueAction extends Action { if (this.value instanceof Variable && stackFrame && session && this.value.evaluateName) { return session.evaluate(this.value.evaluateName, stackFrame.frameId, this.context).then(result => { - this.clipboardService.writeText(result.body.result); + return this.clipboardService.writeText(result.body.result); }, err => this.clipboardService.writeText(this.value.value)); } - this.clipboardService.writeText(this.value); - return Promise.resolve(undefined); + + return this.clipboardService.writeText(this.value); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 95010a4ea63..95cd771b7f3 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -71,11 +71,11 @@ export function registerCommands(): void { CommandsRegistry.registerCommand({ id: COPY_STACK_TRACE_ID, - handler: (accessor: ServicesAccessor, _: string, frame: IStackFrame) => { + handler: async (accessor: ServicesAccessor, _: string, frame: IStackFrame) => { const textResourcePropertiesService = accessor.get(ITextResourcePropertiesService); const clipboardService = accessor.get(IClipboardService); const eol = textResourcePropertiesService.getEOL(frame.source.uri); - clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol)); + await clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol)); } }); diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index 82be95aef9b..df8a68cbc67 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -21,7 +21,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, ITerminalSettings, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; import { Debugger } from 'vs/workbench/contrib/debug/common/debugger'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -108,10 +108,10 @@ export class ConfigurationManager implements IConfigurationManager { return Promise.resolve(config); } - runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments): Promise { let tl = this.debugAdapterFactories.get(debugType); if (tl) { - return tl.runInTerminal(args, config); + return tl.runInTerminal(args); } return Promise.resolve(void 0); } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index ff64d75d22b..b198f1d9e15 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -80,7 +80,7 @@ export class DebugHoverWidget implements IContentWidget { accessibilityProvider: new DebugHoverAccessibilityProvider(), mouseSupport: false, horizontalScrolling: true - }) as any as AsyncDataTree; + }); this.valueContainer = $('.value'); this.valueContainer.tabIndex = 0; diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 0b24d9395b1..1ae35d5a248 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/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index ca53f26dbf5..603797e9d04 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -31,7 +31,6 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; import { onUnexpectedError } from 'vs/base/common/errors'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ISignService } from 'vs/platform/sign/common/sign'; export class DebugSession implements IDebugSession { @@ -66,7 +65,6 @@ export class DebugSession implements IDebugSession { @IViewletService private readonly viewletService: IViewletService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @INotificationService private readonly notificationService: INotificationService, - @ISignService private readonly signService: ISignService, @IProductService private readonly productService: IProductService, @IWindowsService private readonly windowsService: IWindowsService ) { @@ -169,7 +167,7 @@ export class DebugSession implements IDebugSession { return dbgr.createDebugAdapter(this).then(debugAdapter => { - this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.signService, this.windowsService); + this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService); return this.raw!.start().then(() => { diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index 8d31338c44e..70a962e46ec 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -402,7 +402,7 @@ export class LoadedScriptsView extends ViewletPanel { @IDebugService private readonly debugService: IDebugService, @ILabelService private readonly labelService: ILabelService ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('loadedScriptsSection', "Loaded Scripts Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('loadedScriptsSection', "Loaded Scripts Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); this.loadedScriptsItemType = CONTEXT_LOADED_SCRIPTS_ITEM_TYPE.bindTo(contextKeyService); } @@ -433,7 +433,7 @@ export class LoadedScriptsView extends ViewletPanel { accessibilityProvider: new LoadedSciptsAccessibilityProvider(), ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'loadedScriptsAriaLabel' }, "Debug Loaded Scripts"), } - ) as WorkbenchAsyncDataTree; + ); this.tree.setInput(root); diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 23119470129..a0f2120b920 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -12,7 +12,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; -import { ISignService } from 'vs/platform/sign/common/sign'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; @@ -74,7 +73,6 @@ export class RawDebugSession { dbgr: IDebugger, private readonly telemetryService: ITelemetryService, public readonly customTelemetryService: ITelemetryService | undefined, - private readonly signService: ISignService, private readonly windowsService: IWindowsService ) { @@ -126,8 +124,8 @@ export class RawDebugSession { break; case 'capabilities': if (event.body) { - const capabilites = (event).body.capabilities; - this.mergeCapabilities(capabilites); + const capabilities = (event).body.capabilities; + this.mergeCapabilities(capabilities); } break; case 'stopped': @@ -548,19 +546,6 @@ export class RawDebugSession { safeSendResponse(response); }); break; - case 'handshake': - try { - const signature = await this.signService.sign(request.arguments.value); - response.body = { - signature: signature - }; - safeSendResponse(response); - } catch (e) { - response.success = false; - response.message = e.message; - safeSendResponse(response); - } - break; default: response.success = false; response.message = `unknown request '${request.command}'`; @@ -602,7 +587,13 @@ export class RawDebugSession { } } else { - args._.push(a2); + const match = /^--(.+)$/.exec(a2); + if (match && match.length === 2) { + const key = match[1]; + (args)[key] = true; + } else { + args._.push(a2); + } } } } @@ -610,7 +601,10 @@ export class RawDebugSession { let env: IProcessEnvironment = {}; if (vscodeArgs.env) { // merge environment variables into a copy of the process.env - env = objects.mixin(objects.mixin(env, process.env), vscodeArgs.env); + if (typeof process === 'object' && process.env) { + env = objects.mixin(env, process.env); + } + env = objects.mixin(env, vscodeArgs.env); // and delete some if necessary Object.keys(env).filter(k => env[k] === null).forEach(key => delete env[key]); } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 9e89ac09d99..922de4fe53a 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -378,12 +378,19 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.replDelegate = new ReplDelegate(this.configurationService); const wordWrap = this.configurationService.getValue('debug').console.wordWrap; dom.toggleClass(treeContainer, 'word-wrap', wordWrap); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, this.replDelegate, [ - this.instantiationService.createInstance(VariablesRenderer), - this.instantiationService.createInstance(ReplSimpleElementsRenderer), - new ReplExpressionsRenderer(), - new ReplRawObjectsRenderer() - ], new ReplDataSource(), { + this.tree = this.instantiationService.createInstance( + WorkbenchAsyncDataTree, + treeContainer, + this.replDelegate, + [ + this.instantiationService.createInstance(VariablesRenderer), + this.instantiationService.createInstance(ReplSimpleElementsRenderer), + new ReplExpressionsRenderer(), + new ReplRawObjectsRenderer() + ], + // https://github.com/microsoft/TypeScript/issues/32526 + new ReplDataSource() as IAsyncDataSource, + { ariaLabel: nls.localize('replAriaLabel', "Read Eval Print Loop Panel"), accessibilityProvider: new ReplAccessibilityProvider(), identityProvider: { getId: (element: IReplElement) => element.getId() }, @@ -392,7 +399,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati horizontalScrolling: !wordWrap, setRowLineHeight: false, supportDynamicHeights: wordWrap - }) as WorkbenchAsyncDataTree; + }); this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); let lastSelectedString: string; this._register(this.tree.onMouseClick(() => { @@ -472,16 +479,16 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati private onContextMenu(e: ITreeContextMenuEvent): void { const actions: IAction[] = []; - actions.push(new Action('debug.replCopy', nls.localize('copy', "Copy"), undefined, true, () => { + actions.push(new Action('debug.replCopy', nls.localize('copy', "Copy"), undefined, true, async () => { const nativeSelection = window.getSelection(); if (nativeSelection) { - this.clipboardService.writeText(nativeSelection.toString()); + await this.clipboardService.writeText(nativeSelection.toString()); } return Promise.resolve(); })); - actions.push(new Action('workbench.debug.action.copyAll', nls.localize('copyAll', "Copy All"), undefined, true, () => { - this.clipboardService.writeText(this.getVisibleContent()); - return Promise.resolve(undefined); + actions.push(new Action('workbench.debug.action.copyAll', nls.localize('copyAll', "Copy All"), undefined, true, async () => { + await this.clipboardService.writeText(this.getVisibleContent()); + return Promise.resolve(); })); actions.push(new Action('debug.collapseRepl', nls.localize('collapse', "Collapse All"), undefined, true, () => { this.tree.collapseAll(); @@ -902,7 +909,7 @@ class ReplCopyAllAction extends EditorAction { run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { const clipboardService = accessor.get(IClipboardService); - clipboardService.writeText(accessor.get(IPrivateReplService).getVisibleContent()); + return clipboardService.writeText(accessor.get(IPrivateReplService).getVisibleContent()); } } diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index b12ac70119b..71559c50d3c 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -29,6 +29,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const $ = dom.$; let forgetScopes = true; @@ -49,9 +50,10 @@ export class VariablesView extends ViewletPanel { @IKeybindingService keybindingService: IKeybindingService, @IConfigurationService configurationService: IConfigurationService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IClipboardService private readonly clipboardService: IClipboardService + @IClipboardService private readonly clipboardService: IClipboardService, + @IContextKeyService contextKeyService: IContextKeyService ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('variablesSection', "Variables Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('variablesSection', "Variables Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); // Use scheduler to prevent unnecessary flashing this.onFocusStackFrameScheduler = new RunOnceScheduler(() => { @@ -91,7 +93,7 @@ export class VariablesView extends ViewletPanel { accessibilityProvider: new VariablesAccessibilityProvider(), identityProvider: { getId: (element: IExpression | IScope) => element.getId() }, keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e } - }) as WorkbenchAsyncDataTree; + }); this.tree.setInput(this.debugService.getViewModel()).then(null, onUnexpectedError); @@ -164,8 +166,7 @@ export class VariablesView extends ViewletPanel { actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, variable, 'variables')); if (variable.evaluateName) { actions.push(new Action('debug.copyEvaluatePath', nls.localize('copyAsExpression', "Copy as Expression"), undefined, true, () => { - this.clipboardService.writeText(variable.evaluateName!); - return Promise.resolve(); + return this.clipboardService.writeText(variable.evaluateName!); })); actions.push(new Separator()); actions.push(new Action('debug.addToWatchExpressions', nls.localize('addToWatchExpressions', "Add to Watch"), undefined, true, () => { diff --git a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts index 53549128538..7b0430d2504 100644 --- a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts +++ b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts @@ -29,6 +29,7 @@ import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { FuzzyScore } from 'vs/base/common/filters'; import { IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { variableSetEmitter, VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024; @@ -45,8 +46,9 @@ export class WatchExpressionsView extends ViewletPanel { @IKeybindingService keybindingService: IKeybindingService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IConfigurationService configurationService: IConfigurationService, + @IContextKeyService contextKeyService: IContextKeyService, ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('watchExpressionsSection', "Watch Expressions Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('watchExpressionsSection', "Watch Expressions Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); this.onWatchExpressionsUpdatedScheduler = new RunOnceScheduler(() => { this.needsRefresh = false; @@ -66,7 +68,7 @@ export class WatchExpressionsView extends ViewletPanel { identityProvider: { getId: (element: IExpression) => element.getId() }, keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression) => e }, dnd: new WatchExpressionsDragAndDrop(this.debugService), - }) as WorkbenchAsyncDataTree; + }); this.tree.setInput(this.debugService).then(undefined, onUnexpectedError); CONTEXT_WATCH_EXPRESSIONS_FOCUSED.bindTo(this.tree.contextKeyService); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 363f6eeb346..1ac7b96593d 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -24,9 +24,7 @@ import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExte import { Registry } from 'vs/platform/registry/common/platform'; import { TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { ITerminalConfiguration } from 'vs/workbench/contrib/terminal/common/terminal'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExternalTerminalSettings } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; export const VIEWLET_ID = 'workbench.view.debug'; export const VIEW_CONTAINER: ViewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID); @@ -573,12 +571,7 @@ export interface IDebugAdapterTrackerFactory { } export interface ITerminalLauncher { - runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; -} - -export interface ITerminalSettings { - external: IExternalTerminalSettings; - integrated: ITerminalConfiguration; + runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise; } export interface IConfigurationManager { @@ -623,7 +616,7 @@ export interface IConfigurationManager { createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined; substituteVariables(debugType: string, folder: IWorkspaceFolder | undefined, config: IConfig): Promise; - runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments): Promise; } export interface ILaunch { diff --git a/src/vs/workbench/contrib/debug/common/debugger.ts b/src/vs/workbench/contrib/debug/common/debugger.ts index 4034a6c9596..8f317ccc138 100644 --- a/src/vs/workbench/contrib/debug/common/debugger.ts +++ b/src/vs/workbench/contrib/debug/common/debugger.ts @@ -9,7 +9,7 @@ import * as objects from 'vs/base/common/objects'; import { isObject } from 'vs/base/common/types'; import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, ITerminalSettings, IDebugger, IDebugSession, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, IDebugger, IDebugSession, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import * as ConfigurationResolverUtils from 'vs/workbench/services/configurationResolver/common/configurationResolverUtils'; @@ -108,8 +108,7 @@ export class Debugger implements IDebugger { } runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { - const config = this.configurationService.getValue('terminal'); - return this.configurationManager.runInTerminal(this.type, args, config); + return this.configurationManager.runInTerminal(this.type, args); } get label(): string { diff --git a/src/vs/workbench/contrib/debug/node/telemetryApp.ts b/src/vs/workbench/contrib/debug/node/telemetryApp.ts index affab685550..52507e4fd20 100644 --- a/src/vs/workbench/contrib/debug/node/telemetryApp.ts +++ b/src/vs/workbench/contrib/debug/node/telemetryApp.ts @@ -8,7 +8,7 @@ import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppen import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc'; const appender = new AppInsightsAppender(process.argv[2], JSON.parse(process.argv[3]), process.argv[4]); -process.once('exit', () => appender.dispose()); +process.once('exit', () => appender.flush()); const channel = new TelemetryAppenderChannel(appender); const server = new Server('telemetry'); diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index 6f173a4864f..7813de75b26 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -5,15 +5,15 @@ import * as cp from 'child_process'; import * as env from 'vs/base/common/platform'; -import { ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; import { getSystemShell } from 'vs/workbench/contrib/terminal/node/terminal'; import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; +import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; let externalTerminalService: IExternalTerminalService | undefined = undefined; -export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): void { +export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): void { if (!externalTerminalService) { if (env.isWindows) { externalTerminalService = new WindowsExternalTerminalService(undefined); @@ -24,6 +24,7 @@ export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestAr } } if (externalTerminalService) { + const config = configProvider.getConfiguration('terminal'); externalTerminalService.runInTerminal(args.title!, args.cwd, args.args, args.env || {}, config.external || {}); } } @@ -60,24 +61,25 @@ export function hasChildProcesses(processId: number): boolean { const enum ShellType { cmd, powershell, bash } -export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): string { +export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, shell: string, configProvider: ExtHostConfigProvider): string { - let shellType: ShellType; + let shellType = env.isWindows ? ShellType.cmd : ShellType.bash; // pick a good default - // get the shell configuration for the current platform - let shell: string; - const shell_config = config.integrated.shell; - if (env.isWindows) { - shell = shell_config.windows || getSystemShell(env.Platform.Windows); - shellType = ShellType.cmd; - } else if (env.isLinux) { - shell = shell_config.linux || getSystemShell(env.Platform.Linux); - shellType = ShellType.bash; - } else if (env.isMacintosh) { - shell = shell_config.osx || getSystemShell(env.Platform.Mac); - shellType = ShellType.bash; - } else { - throw new Error('Unknown platform'); + if (shell) { + + const config = configProvider.getConfiguration('terminal'); + + // get the shell configuration for the current platform + const shell_config = config.integrated.shell; + if (env.isWindows) { + shell = shell_config.windows || getSystemShell(env.Platform.Windows); + } else if (env.isLinux) { + shell = shell_config.linux || getSystemShell(env.Platform.Linux); + } else if (env.isMacintosh) { + shell = shell_config.osx || getSystemShell(env.Platform.Mac); + } else { + throw new Error('Unknown platform'); + } } // try to determine the shell type diff --git a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts index 7aafdc899f3..6b313596ca6 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts @@ -15,7 +15,7 @@ import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; import { IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug'; function createMockSession(model: DebugModel, name = 'mockSession', parentSession?: DebugSession | undefined): DebugSession { - return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); + return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); } suite('Debug - Model', () => { @@ -427,7 +427,7 @@ suite('Debug - Model', () => { // Repl output test('repl output', () => { - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); const repl = new ReplModel(session); repl.appendToRepl('first line\n', severity.Error); repl.appendToRepl('second line ', severity.Error); diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts new file mode 100644 index 00000000000..437afe18bd6 --- /dev/null +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Event } from 'vs/base/common/event'; + +export const enum ExperimentState { + Evaluating, + NoRun, + Run, + Complete +} + +export interface IExperimentAction { + type: ExperimentActionType; + properties: any; +} + +export enum ExperimentActionType { + Custom = 'Custom', + Prompt = 'Prompt', + AddToRecommendations = 'AddToRecommendations', + ExtensionSearchResults = 'ExtensionSearchResults' +} + +export type LocalizedPromptText = { [locale: string]: string; }; + +export interface IExperimentActionPromptProperties { + promptText: string | LocalizedPromptText; + commands: IExperimentActionPromptCommand[]; +} + +export interface IExperimentActionPromptCommand { + text: string | { [key: string]: string }; + externalLink?: string; + curatedExtensionsKey?: string; + curatedExtensionsList?: string[]; +} + +export interface IExperiment { + id: string; + enabled: boolean; + state: ExperimentState; + action?: IExperimentAction; +} + +export interface IExperimentService { + _serviceBrand: any; + getExperimentById(id: string): Promise; + getExperimentsByType(type: ExperimentActionType): Promise; + getCuratedExtensionsList(curatedExtensionsKey: string): Promise; + markAsCompleted(experimentId: string): void; + + onExperimentEnabled: Event; +} + +export const IExperimentService = createDecorator('experimentService'); \ No newline at end of file diff --git a/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts b/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts index 71c3992d276..79dd609cb60 100644 --- a/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts @@ -3,27 +3,24 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import product from 'vs/platform/product/node/product'; - -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IRequestService } from 'vs/platform/request/node/request'; import { language } from 'vs/base/common/platform'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; -import { asJson } from 'vs/base/node/request'; +import { IRequestService, asJson } from 'vs/platform/request/common/request'; import { Emitter, Event } from 'vs/base/common/event'; import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; -import { WorkspaceStats } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats'; import { CancellationToken } from 'vs/base/common/cancellation'; import { distinct } from 'vs/base/common/arrays'; -import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { ExperimentState, IExperimentAction, IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { IProductService } from 'vs/platform/product/common/product'; +import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService'; interface IExperimentStorageState { enabled: boolean; @@ -32,13 +29,6 @@ interface IExperimentStorageState { lastEditedDate?: string; } -export const enum ExperimentState { - Evaluating, - NoRun, - Run, - Complete -} - interface IRawExperiment { id: string; enabled?: boolean; @@ -65,57 +55,11 @@ interface IRawExperiment { action?: IExperimentAction; } -interface IExperimentAction { - type: ExperimentActionType; - properties: any; -} - -export enum ExperimentActionType { - Custom = 'Custom', - Prompt = 'Prompt', - AddToRecommendations = 'AddToRecommendations', - ExtensionSearchResults = 'ExtensionSearchResults' -} - -export type LocalizedPromptText = { [locale: string]: string; }; - -export interface IExperimentActionPromptProperties { - promptText: string | LocalizedPromptText; - commands: IExperimentActionPromptCommand[]; -} - -export interface IExperimentActionPromptCommand { - text: string | { [key: string]: string }; - externalLink?: string; - curatedExtensionsKey?: string; - curatedExtensionsList?: string[]; -} - -export interface IExperiment { - id: string; - enabled: boolean; - state: ExperimentState; - action?: IExperimentAction; -} - -export interface IExperimentService { - _serviceBrand: any; - getExperimentById(id: string): Promise; - getExperimentsByType(type: ExperimentActionType): Promise; - getCuratedExtensionsList(curatedExtensionsKey: string): Promise; - markAsCompleted(experimentId: string): void; - - onExperimentEnabled: Event; -} - -export const IExperimentService = createDecorator('experimentService'); - export class ExperimentService extends Disposable implements IExperimentService { _serviceBrand: any; private _experiments: IExperiment[] = []; private _loadExperimentsPromise: Promise; private _curatedMapping = Object.create(null); - private _disposables: IDisposable[] = []; private readonly _onExperimentEnabled = this._register(new Emitter()); onExperimentEnabled: Event = this._onExperimentEnabled.event; @@ -128,7 +72,9 @@ export class ExperimentService extends Disposable implements IExperimentService @ITelemetryService private readonly telemetryService: ITelemetryService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IRequestService private readonly requestService: IRequestService, - @IConfigurationService private readonly configurationService: IConfigurationService + @IConfigurationService private readonly configurationService: IConfigurationService, + @IProductService private readonly productService: IProductService, + @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService ) { super(); @@ -172,10 +118,10 @@ export class ExperimentService extends Disposable implements IExperimentService } protected getExperiments(): Promise { - if (!product.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) { + if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) { return Promise.resolve([]); } - return this.requestService.request({ type: 'GET', url: product.experimentsUrl }, CancellationToken.None).then(context => { + return this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None).then(context => { if (context.res.statusCode !== 200) { return Promise.resolve(null); } @@ -274,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 }); }); }); } @@ -411,7 +355,7 @@ export class ExperimentService extends Disposable implements IExperimentService onSaveHandler.dispose(); return; } - e.forEach(event => { + e.forEach(async event => { if (event.kind !== StateChange.SAVED || latestExperimentState.state !== ExperimentState.Evaluating || date === latestExperimentState.lastEditedDate @@ -426,10 +370,12 @@ export class ExperimentService extends Disposable implements IExperimentService filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath); } if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) { - workspaceCheck = !!WorkspaceStats.TAGS && fileEdits.workspaceIncludes.some(x => !!WorkspaceStats.TAGS[x]); + const tags = await this.workspaceStatsService.getTags(); + workspaceCheck = !!tags && fileEdits.workspaceIncludes.some(x => !!tags[x]); } if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) { - workspaceCheck = !!WorkspaceStats.TAGS && !fileEdits.workspaceExcludes.some(x => !!WorkspaceStats.TAGS[x]); + const tags = await this.workspaceStatsService.getTags(); + workspaceCheck = !!tags && !fileEdits.workspaceExcludes.some(x => !!tags[x]); } if (filePathCheck && workspaceCheck) { latestExperimentState.editCount = (latestExperimentState.editCount || 0) + 1; @@ -445,14 +391,10 @@ export class ExperimentService extends Disposable implements IExperimentService } } }); - this._disposables.push(onSaveHandler); + this._register(onSaveHandler); return ExperimentState.Evaluating; }); } - - dispose() { - this._disposables = dispose(this._disposables); - } } diff --git a/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts b/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts index 3581351f6e0..97f55700a40 100644 --- a/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts +++ b/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts @@ -5,7 +5,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification'; -import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties, IExperimentActionPromptCommand, ExperimentState } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties, IExperimentActionPromptCommand, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; diff --git a/src/vs/workbench/contrib/experiments/electron-browser/experiments.contribution.ts b/src/vs/workbench/contrib/experiments/electron-browser/experiments.contribution.ts index f3dcaf5074e..ca28e9b6f67 100644 --- a/src/vs/workbench/contrib/experiments/electron-browser/experiments.contribution.ts +++ b/src/vs/workbench/contrib/experiments/electron-browser/experiments.contribution.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IExperimentService, ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; 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 d98057ee111..f44b4d3904e 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 @@ -4,20 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { ExperimentService, ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; 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'; import { URLService } from 'vs/platform/url/common/urlService'; import { IURLService } from 'vs/platform/url/common/url'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -25,7 +26,6 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; diff --git a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts index ec566e9c57a..781fc5ab7c0 100644 --- a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts +++ b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts @@ -13,7 +13,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt'; -import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/common/experimentService'; import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test'; import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices'; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts similarity index 97% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts rename to src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 08929e250d5..e2c7032f0f6 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -20,16 +20,15 @@ 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'; import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions'; -import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets'; +import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, ExtensionToolTipAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -44,7 +43,7 @@ import { assign } from 'vs/base/common/objects'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionsTree, ExtensionData } from 'vs/workbench/contrib/extensions/browser/extensionsViewer'; -import { ShowCurrentReleaseNotesAction } from 'vs/workbench/contrib/update/electron-browser/update'; +import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -52,6 +51,7 @@ import { getDefaultValue } from 'vs/platform/configuration/common/configurationR import { isUndefined } from 'vs/base/common/types'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { URI } from 'vs/base/common/uri'; +import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview'; function renderBody(body: string): string { const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://'); @@ -194,8 +194,8 @@ export class ExtensionEditor extends BaseEditor { @IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService, @IStorageService storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, - @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService - + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, + @IWebviewService private readonly webviewService: IWebviewService ) { super(ExtensionEditor.ID, telemetryService, themeService, storageService); this.extensionReadme = null; @@ -376,7 +376,7 @@ export class ExtensionEditor extends BaseEditor { this.instantiationService.createInstance(LocalInstallAction), combinedInstallAction, systemDisabledWarningAction, - this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction), + this.instantiationService.createInstance(ExtensionToolTipAction, systemDisabledWarningAction, reloadAction), this.instantiationService.createInstance(MaliciousStatusLabelAction, true), ]; const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]); @@ -483,6 +483,13 @@ export class ExtensionEditor extends BaseEditor { })); } + clearInput(): void { + this.contentDisposables.clear(); + this.transientDisposables.clear(); + + super.clearInput(); + } + focus(): void { if (this.activeElement) { this.activeElement.focus(); @@ -490,8 +497,8 @@ export class ExtensionEditor extends BaseEditor { } showFind(): void { - if (this.activeElement instanceof WebviewElement) { - this.activeElement.showFind(); + if (this.activeElement && (this.activeElement).showFind) { + (this.activeElement).showFind(); } } @@ -537,7 +544,7 @@ export class ExtensionEditor extends BaseEditor { .then(renderBody) .then(removeEmbeddedSVGs) .then(body => { - const webviewElement = this.instantiationService.createInstance(WebviewElement, + const webviewElement = this.webviewService.createWebview('extensionEditor', { enableFindWidget: true, }, @@ -558,7 +565,7 @@ export class ExtensionEditor extends BaseEditor { return; } // Whitelist supported schemes for links - if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesAction.ID)) { + if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesActionId)) { this.openerService.open(link); } }, null, this.contentDisposables)); @@ -843,7 +850,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; } @@ -926,12 +933,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); } }); }); @@ -947,12 +954,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); } }); @@ -1006,12 +1013,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; } }); @@ -1020,12 +1027,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; } }); @@ -1067,11 +1074,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 00000000000..32bd703fba0 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -0,0 +1,381 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. 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'; +import { RemoteExtensionsInstaller } from 'vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller'; + +// 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 +Registry.as(EditorExtensions.Editors).registerEditor( + new EditorDescriptor( + ExtensionEditor, + ExtensionEditor.ID, + localize('extension', "Extension") + ), + [ + 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 + }, + 'extensions.confirmedUriHandlerExtensionIds': { + type: 'array', + description: localize('handleUriConfirmedExtensions', "When an extension is listed here, a confirmation prompt will not be shown when that extension handles a URI."), + default: [] + } + } + }); + +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); +workbenchRegistry.registerWorkbenchContribution(RemoteExtensionsInstaller, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts similarity index 87% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index fe4f91ede5c..fdb0056d228 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -15,7 +15,8 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { dispose, Disposable } from 'vs/base/common/lifecycle'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG } 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, IExtensionManagementServer } 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'; @@ -54,15 +55,15 @@ 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'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; -function toExtensionDescription(local: ILocalExtension): IExtensionDescription { +export function toExtensionDescription(local: ILocalExtension): IExtensionDescription { return { identifier: new ExtensionIdentifier(local.identifier.id), isBuiltin: local.type === ExtensionType.System, @@ -73,7 +74,8 @@ function toExtensionDescription(local: ILocalExtension): IExtensionDescription { }; } -const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error, instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => { +const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error, + instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => { if (!extension || error.name === INSTALL_ERROR_INCOMPATIBLE || error.name === INSTALL_ERROR_MALICIOUS || !productService.extensionsGallery) { return Promise.reject(error); } else { @@ -162,10 +164,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(); @@ -173,19 +175,22 @@ export class InstallAction extends ExtensionAction { } update(): void { - if (!this.extension || this.extension.type === ExtensionType.System || this.extension.state === ExtensionState.Installed) { - this.enabled = false; - this.class = InstallAction.Class; - this.label = InstallAction.INSTALL_LABEL; - return; - } this.enabled = false; - if (this.extensionsWorkbenchService.canInstall(this.extension)) { - const local = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0]; - this.enabled = !local || (!!local.local && isLanguagePackExtension(local.local.manifest)); + this.class = InstallAction.Class; + this.label = InstallAction.INSTALL_LABEL; + if (this.extension && this.extension.type === ExtensionType.User) { + if (this.extension.state === ExtensionState.Uninstalled && this.extensionsWorkbenchService.canInstall(this.extension)) { + this.enabled = true; + this.updateLabel(); + return; + } + if (this.extension.state === ExtensionState.Installing) { + this.enabled = false; + this.updateLabel(); + this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class; + return; + } } - this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class; - this.updateLabel(); } private updateLabel(): void { @@ -193,12 +198,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}`; } @@ -271,157 +276,94 @@ export class InstallAction extends ExtensionAction { } } -export class RemoteInstallAction extends ExtensionAction { +export abstract class InstallInOtherServerAction extends ExtensionAction { - private static INSTALL_LABEL = localize('install', "Install"); - private static INSTALLING_LABEL = localize('installing', "Installing"); + protected static INSTALL_LABEL = localize('install', "Install"); + protected static INSTALLING_LABEL = localize('installing', "Installing"); private static readonly Class = 'extension-action prominent install'; private static readonly InstallingClass = 'extension-action install installing'; updateWhenCounterExtensionChanges: boolean = true; - private installing: boolean = false; constructor( + id: string, + private readonly server: IExtensionManagementServer | null, @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, ) { - super(`extensions.remoteinstall`, RemoteInstallAction.INSTALL_LABEL, RemoteInstallAction.Class, false); - this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this)); - this.updateLabel(); + super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false); this.update(); } - private updateLabel(): void { - if (this.installing) { - this.label = RemoteInstallAction.INSTALLING_LABEL; - 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}`; - this.tooltip = this.label; - return; - } - } - update(): void { this.enabled = false; - this.class = RemoteInstallAction.Class; - if (this.installing) { - this.enabled = true; - this.class = RemoteInstallAction.InstallingClass; - this.updateLabel(); - return; - } - if (this.environmentService.configuration.remoteAuthority - // Installed User Extension - && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed - // Local Workspace Extension - && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) - // Extension does not exist in remote - && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer) - && this.extensionsWorkbenchService.canInstall(this.extension) + this.class = InstallInOtherServerAction.Class; + + if ( + this.extension && this.extension.local && this.server && this.extension.state === ExtensionState.Installed && this.extension.type === ExtensionType.User + // disabled by extension kind or it is a language pack extension + && (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest)) ) { - this.enabled = true; - this.updateLabel(); - return; + const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server)[0]; + if (extensionInOtherServer) { + // Getting installed in other server + if (extensionInOtherServer.state === ExtensionState.Installing && !extensionInOtherServer.local) { + this.enabled = true; + this.label = InstallInOtherServerAction.INSTALLING_LABEL; + this.class = InstallInOtherServerAction.InstallingClass; + } + } else { + // Not installed in other server + this.enabled = true; + this.label = this.getInstallLabel(); + } } } async run(): Promise { - if (this.extensionManagementServerService.remoteExtensionManagementServer && !this.installing) { - this.installing = true; - this.update(); + if (this.server) { this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); if (this.extension.gallery) { - await this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery); - this.installing = false; - this.update(); + await this.server.extensionManagementService.installFromGallery(this.extension.gallery); + } else { + const vsix = await this.extension.server!.extensionManagementService.zip(this.extension.local!); + await this.server.extensionManagementService.install(vsix); } } } + + protected abstract getInstallLabel(): string; } -export class LocalInstallAction extends ExtensionAction { - - private static INSTALL_LABEL = localize('install locally', "Install Locally"); - private static INSTALLING_LABEL = localize('installing', "Installing"); - - private static readonly Class = 'extension-action prominent install'; - private static readonly InstallingClass = 'extension-action install installing'; - - updateWhenCounterExtensionChanges: boolean = true; - private installing: boolean = false; +export class RemoteInstallAction extends InstallInOtherServerAction { 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, + @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { - super(`extensions.localinstall`, LocalInstallAction.INSTALL_LABEL, LocalInstallAction.Class, false); - this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this)); - this.updateLabel(); - this.update(); + super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, extensionsWorkbenchService); } - private updateLabel(): void { - if (this.installing) { - this.label = LocalInstallAction.INSTALLING_LABEL; - this.tooltip = this.label; - return; - } - this.label = `${LocalInstallAction.INSTALL_LABEL}`; - this.tooltip = this.label; + protected getInstallLabel(): string { + return this.extensionManagementServerService.remoteExtensionManagementServer ? localize('Install on Server', "Install on {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label) : InstallInOtherServerAction.INSTALL_LABEL; } - update(): void { - this.enabled = false; - this.class = LocalInstallAction.Class; - if (this.installing) { - this.enabled = true; - this.class = LocalInstallAction.InstallingClass; - this.updateLabel(); - return; - } - if (this.environmentService.configuration.remoteAuthority - // Installed User Extension - && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed - // Remote UI or Language pack Extension - && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) - // Extension does not exist in local - && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer) - && this.extensionsWorkbenchService.canInstall(this.extension) - ) { - this.enabled = true; - this.updateLabel(); - return; - } +} + +export class LocalInstallAction extends InstallInOtherServerAction { + + constructor( + @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService + ) { + super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, extensionsWorkbenchService); } - async run(): Promise { - if (!this.installing) { - this.installing = true; - this.update(); - this.extensionsWorkbenchService.open(this.extension); - alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); - if (this.extension.gallery) { - await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery); - this.installing = false; - this.update(); - } - } + protected getInstallLabel(): string { + return localize('install locally', "Install Locally"); } + } export class UninstallAction extends ExtensionAction { @@ -857,8 +799,7 @@ export class ExtensionInfoAction extends ExtensionAction { const clipboardStr = `${name}\n${id}\n${description}\n${verision}\n${publisher}${link ? '\n' + link : ''}`; - this.clipboardService.writeText(clipboardStr); - return Promise.resolve(); + return this.clipboardService.writeText(clipboardStr); } } @@ -898,13 +839,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); } } @@ -924,12 +867,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); } } @@ -949,13 +894,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); } } @@ -974,13 +921,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); } } @@ -1062,6 +1011,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 ) { @@ -1077,7 +1027,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."); @@ -1206,10 +1156,7 @@ export class ReloadAction extends ExtensionAction { @IWindowService private readonly windowService: IWindowService, @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, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false); this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); @@ -1246,7 +1193,7 @@ export class ReloadAction extends ExtensionAction { const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); if (isUninstalled) { - if (isSameExtensionRunning) { + if (isSameExtensionRunning && !this.extensionService.canRemoveExtension(runningExtension)) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('postUninstallTooltip', "Please reload Visual Studio Code to complete the uninstallation of this extension."); @@ -1256,8 +1203,9 @@ export class ReloadAction extends ExtensionAction { } if (this.extension.local) { const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local); + + // Extension is runningÃŽ if (runningExtension) { - // Extension is running if (isEnabled) { if (!this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) { if (isSameExtensionRunning) { @@ -1280,39 +1228,27 @@ export class ReloadAction extends ExtensionAction { } } return; - } else { - // Extension is not running + } + + // Extension is not running + else { if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension."); return; } - if (this.workbenchEnvironmentService.configuration.remoteAuthority) { - const uiExtension = isUIExtension(this.extension.local.manifest, this.productService, this.configurationService); - // Local Workspace Extension - if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) { - const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0]; - // Extension exist in remote and enabled - if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) { - this.enabled = true; - this.label = localize('reloadRequired', "Reload Required"); - this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension."); - alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName)); - return; - } - } - // Remote UI Extension - if (uiExtension && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) { - const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)[0]; - // Extension exist in local and enabled - if (localExtension && localExtension.local && this.extensionEnablementService.isEnabled(localExtension.local)) { - this.enabled = true; - this.label = localize('reloadRequired', "Reload Required"); - this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension."); - alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName)); - return; - } + + const otherServer = this.extension.server ? this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null; + if (otherServer && this.extension.enablementState === EnablementState.DisabledByExtensionKind) { + const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === otherServer)[0]; + // Same extension in other server exists and + if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) { + this.enabled = true; + this.label = localize('reloadRequired', "Reload Required"); + this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension."); + alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName)); + return; } } } @@ -1717,8 +1653,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; @@ -1756,7 +1694,7 @@ export class InstallRecommendedExtensionAction extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { - viewlet.search('@recommended '); + viewlet.search(`@id:${this.extensionId}`); viewlet.focus(); return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None) .then(pager => { @@ -2523,8 +2461,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; } @@ -2567,7 +2505,7 @@ export class MaliciousStatusLabelAction extends ExtensionAction { } } -export class DisabledLabelAction extends ExtensionAction { +export class ExtensionToolTipAction extends ExtensionAction { private static readonly Class = 'disable-status'; @@ -2576,10 +2514,12 @@ export class DisabledLabelAction extends ExtensionAction { constructor( private readonly warningAction: SystemDisabledWarningAction, + private readonly reloadAction: ReloadAction, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IExtensionService private readonly extensionService: IExtensionService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { - super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false); + super('extensions.tooltip', warningAction.tooltip, `${ExtensionToolTipAction.Class} hide`, false); this._register(warningAction.onDidChange(() => this.update(), this)); this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); this.updateRunningExtensions(); @@ -2590,25 +2530,51 @@ export class DisabledLabelAction extends ExtensionAction { } update(): void { - this.class = `${DisabledLabelAction.Class} hide`; - this.label = ''; + this.label = this.getTooltip(); + this.class = ExtensionToolTipAction.Class; + if (!this.label) { + this.class = `${ExtensionToolTipAction.Class} hide`; + } + } + + private getTooltip(): string { + if (!this.extension) { + return ''; + } + if (this.reloadAction.enabled) { + return this.reloadAction.tooltip; + } if (this.warningAction.tooltip) { - this.class = DisabledLabelAction.Class; - this.label = this.warningAction.tooltip; - return; + return this.warningAction.tooltip; } - if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) { - return; - } - if (this.extension && this.extension.local && this._runningExtensions) { + if (this.extension && this.extension.local && this.extension.state === ExtensionState.Installed && this._runningExtensions) { + const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier)); const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local); - const isExtensionRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier)); - if (!isExtensionRunning && !isEnabled && this.extensionEnablementService.canChangeEnablement(this.extension.local)) { - this.class = DisabledLabelAction.Class; - this.label = localize('disabled by user', "This extension is disabled by the user."); - return; + + if (isEnabled && isRunning) { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) { + return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.extension.server.label); + } + } + if (this.extension.enablementState === EnablementState.EnabledGlobally) { + return localize('globally enabled', "This extension is enabled globally."); + } + if (this.extension.enablementState === EnablementState.EnabledWorkspace) { + return localize('workspace enabled', "This extension is enabled for this workspace by the user."); + } + } + + if (!isEnabled && !isRunning) { + if (this.extension.enablementState === EnablementState.DisabledGlobally) { + return localize('globally disabled', "This extension is disabled globally by the user."); + } + if (this.extension.enablementState === EnablementState.DisabledWorkspace) { + return localize('workspace disabled', "This extension is disabled for this workspace by the user."); + } } } + return ''; } run(): Promise { @@ -2630,7 +2596,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, ) { @@ -2653,8 +2618,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; @@ -2663,7 +2627,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; @@ -2675,19 +2639,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) { @@ -2698,12 +2662,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); } @@ -2726,11 +2684,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); } } @@ -2743,7 +2701,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(); @@ -2752,11 +2711,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); } } @@ -2777,11 +2736,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); } } @@ -2804,11 +2763,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); } } @@ -2828,18 +2787,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(); } } @@ -2854,6 +2817,7 @@ export class InstallVSIXAction extends Action { @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @INotificationService private readonly notificationService: INotificationService, @IWindowService private readonly windowService: IWindowService, + @IFileDialogService private readonly fileDialogService: IFileDialogService, @IExtensionService private readonly extensionService: IExtensionService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { @@ -2861,11 +2825,11 @@ export class InstallVSIXAction extends Action { } run(): Promise { - return Promise.resolve(this.windowService.showOpenDialog({ + return Promise.resolve(this.fileDialogService.showOpenDialog({ title: localize('installFromVSIX', "Install from VSIX"), filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }], - properties: ['openFile'], - buttonLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install")) + canSelectFiles: true, + openLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install")) })).then(result => { if (!result) { return Promise.resolve(); @@ -2875,8 +2839,8 @@ export class InstallVSIXAction extends Action { .then(extensions => { for (const extension of extensions) { const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local))); - const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.identifier.id) - : localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id); + const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.displayName || extension.name) + : localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.displayName || extension.name); const actions = requireReload ? [{ label: localize('InstallVSIXAction.reloadNow', "Reload Now"), run: () => this.windowService.reloadWindow() @@ -2973,7 +2937,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); } @@ -2995,7 +2960,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[] })[]> { @@ -3045,6 +3010,119 @@ export class InstallSpecificVersionOfExtensionAction extends Action { } } +interface IExtensionPickItem extends IQuickPickItem { + extension?: IExtension; +} + +export class InstallLocalExtensionsOnRemoteAction extends Action { + + constructor( + @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @INotificationService private readonly notificationService: INotificationService, + @IWindowService private readonly windowService: IWindowService, + @IProgressService private readonly progressService: IProgressService, + @IInstantiationService private readonly instantiationService: IInstantiationService + ) { + super('workbench.extensions.actions.installLocalExtensionsOnRemote'); + this.update(); + this._register(this.extensionsWorkbenchService.onChange(() => this.update())); + } + + get label(): string { + return this.extensionManagementServerService.remoteExtensionManagementServer ? + localize('install local extensions', "Install Local Extensions on {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label) : ''; + } + + private update(): void { + this.enabled = this.getLocalExtensionsToInstall().length > 0; + } + + private getLocalExtensionsToInstall(): IExtension[] { + return this.extensionsWorkbenchService.local.filter(extension => { + const action = this.instantiationService.createInstance(RemoteInstallAction); + action.extension = extension; + return action.enabled; + }); + } + + async run(): Promise { + this.selectAndInstallLocalExtensions(); + return Promise.resolve(); + } + + private selectAndInstallLocalExtensions(): void { + const quickPick = this.quickInputService.createQuickPick(); + quickPick.busy = true; + const disposable = quickPick.onDidAccept(() => { + disposable.dispose(); + quickPick.hide(); + quickPick.dispose(); + this.onDidAccept(quickPick.selectedItems); + }); + quickPick.show(); + const localExtensionsToInstall = this.getLocalExtensionsToInstall(); + quickPick.busy = false; + if (localExtensionsToInstall.length) { + quickPick.placeholder = localize('select extensions to install', "Select extensions to install"); + quickPick.canSelectMany = true; + localExtensionsToInstall.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName)); + quickPick.items = localExtensionsToInstall.map(extension => ({ extension, label: extension.displayName, description: extension.version })); + } else { + quickPick.hide(); + quickPick.dispose(); + this.notificationService.notify({ + severity: Severity.Info, + message: localize('no local extensions', "There are no extensions to install.") + }); + } + } + + private onDidAccept(selectedItems: ReadonlyArray): void { + if (selectedItems.length) { + const localExtensionsToInstall = selectedItems.filter(r => !!r.extension).map(r => r.extension!); + if (localExtensionsToInstall.length) { + this.progressService.withProgress( + { + location: ProgressLocation.Notification, + title: localize('installing extensions', "Installing Extensions...") + }, + () => this.installLocalExtensions(localExtensionsToInstall)); + } + } + } + + private async installLocalExtensions(localExtensionsToInstall: IExtension[]): Promise { + const galleryExtensions: IGalleryExtension[] = []; + const vsixs: URI[] = []; + await Promise.all(localExtensionsToInstall.map(async extension => { + if (this.extensionGalleryService.isEnabled()) { + const gallery = await this.extensionGalleryService.getCompatibleExtension(extension.identifier, extension.version); + if (gallery) { + galleryExtensions.push(gallery); + return; + } + } + const vsix = await this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.zip(extension.local!); + vsixs.push(vsix); + })); + + await Promise.all(galleryExtensions.map(gallery => this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.installFromGallery(gallery))); + await Promise.all(vsixs.map(vsix => this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.install(vsix))); + + this.notificationService.notify({ + severity: Severity.Info, + message: localize('finished installing', "Completed installing the extensions. Please reload the window now."), + actions: { + primary: [new Action('realod', localize('reload', "Realod Window"), '', true, + () => this.windowService.reloadWindow())] + } + }); + } +} + CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsForLanguage', function (accessor: ServicesAccessor, fileExtension: string) { const viewletService = accessor.get(IViewletService); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsDependencyChecker.ts b/src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionsDependencyChecker.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts similarity index 94% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 78fca332fc1..3d9bf40bf98 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -13,11 +13,11 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { Event } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; +import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, ExtensionToolTipAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets'; +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'; @@ -102,8 +102,8 @@ export class Renderer implements IPagedRenderer { systemDisabledWarningAction, this.instantiationService.createInstance(ManageExtensionAction) ]; - const disabledLabelAction = this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction); - const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget, reloadAction); + const extensionTooltipAction = this.instantiationService.createInstance(ExtensionToolTipAction, systemDisabledWarningAction, reloadAction); + const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, extensionTooltipAction, recommendationWidget); const widgets = [ recommendationWidget, iconRemoteBadgeWidget, @@ -113,10 +113,10 @@ export class Renderer implements IPagedRenderer { this.instantiationService.createInstance(InstallCountWidget, installCount, true), this.instantiationService.createInstance(RatingsWidget, ratings, true) ]; - const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, disabledLabelAction]); + const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, extensionTooltipAction]); actionbar.push(actions, actionOptions); - const disposables = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers, disabledLabelAction); + const disposables = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers, extensionTooltipAction); return { root, element, icon, name, installCount, ratings, author, description, disposables: [disposables], actionbar, diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts index 31b80683eed..8747ad8ca51 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts @@ -255,8 +255,10 @@ export class ExtensionData implements IExtensionData { toQuery.push(id); } } - const galleryResult = await this.extensionsWorkbenchService.queryGallery({ names: toQuery, pageSize: toQuery.length }, CancellationToken.None); - result.push(...galleryResult.firstPage); + if (toQuery.length) { + const galleryResult = await this.extensionsWorkbenchService.queryGallery({ names: toQuery, pageSize: toQuery.length }, CancellationToken.None); + result.push(...galleryResult.firstPage); + } return result.map(extension => new ExtensionData(extension, this, this.getChildrenExtensionIds, this.extensionsWorkbenchService)); } return null; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts similarity index 89% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 3523014aa0b..9bed184ac05 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { timeout, Delayer } from 'vs/base/common/async'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { Event as EventOf, Emitter } from 'vs/base/common/event'; import { IAction } from 'vs/base/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -18,20 +18,21 @@ import { append, $, addClass, toggleClass, Dimension } from 'vs/base/browser/dom import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, ExtensionState, AutoUpdateConfigurationKey, ShowRecommendationsOnlyOnDemandKey, CloseExtensionDetailsOnViewChangeKey, VIEW_CONTAINER } from '../common/extensions'; +import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, AutoUpdateConfigurationKey, ShowRecommendationsOnlyOnDemandKey, CloseExtensionDetailsOnViewChangeKey, VIEW_CONTAINER } from '../common/extensions'; import { ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, - EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction -} from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; -import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; + EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, InstallLocalExtensionsOnRemoteAction +} from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +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 './extensionsViews'; +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'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import Severity from 'vs/base/common/severity'; -import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewsRegistry, IViewDescriptor, Extensions } from 'vs/workbench/common/views'; @@ -54,9 +55,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' 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 { RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { ILabelService } from 'vs/platform/label/common/label'; import { MementoObject } from 'vs/workbench/common/memento'; @@ -96,7 +95,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService ) { this.registerViews(); } @@ -116,7 +114,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)); } @@ -144,7 +144,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id, name: viewIdNameMappings[id], ctorDescriptor: { ctor: EnabledExtensionsView }, - when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')), + when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')), weight: 40, canToggleVisibility: true, order: 1 @@ -159,7 +159,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id, name: viewIdNameMappings[id], ctorDescriptor: { ctor: DisabledExtensionsView }, - when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')), + when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')), weight: 10, canToggleVisibility: true, order: 3, @@ -183,15 +183,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(); }, @@ -208,7 +208,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id: `extensions.${server.authority}.default`, get name() { return getInstalledViewName(); }, ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map(onDidChangeServerLabel, () => getInstalledViewName())] }, - when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')), + when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.notEqualsTo('')), weight: 40, order: 1 }]; @@ -339,7 +339,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio private extensionsBox: HTMLElement; private primaryActions: IAction[]; private secondaryActions: IAction[] | null; - private disposables: IDisposable[] = []; private readonly searchViewletState: MementoObject; constructor( @@ -349,6 +348,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio @IInstantiationService instantiationService: IInstantiationService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @INotificationService private readonly notificationService: INotificationService, @IViewletService private readonly viewletService: IViewletService, @IThemeService themeService: IThemeService, @@ -374,14 +374,14 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue(ShowRecommendationsOnlyOnDemandKey)); - this.disposables.push(this.viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables)); + this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this)); this.searchViewletState = this.getMemento(StorageScope.WORKSPACE); this.extensionManagementService.getInstalled(ExtensionType.User).then(result => { this.hasInstalledExtensionsContextKey.set(result.length > 0); }); - this.configurationService.onDidChangeConfiguration(e => { + this._register(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(AutoUpdateConfigurationKey)) { this.secondaryActions = null; this.updateTitleArea(); @@ -389,7 +389,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) { this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue(ShowRecommendationsOnlyOnDemandKey)); } - }, this, this.disposables); + }, this)); } create(parent: HTMLElement): void { @@ -401,7 +401,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio const placeholder = localize('searchExtensions', "Search Extensions in Marketplace"); const searchValue = this.searchViewletState['query.value'] ? this.searchViewletState['query.value'] : ''; - this.searchBox = this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, { + this.searchBox = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, { triggerCharacters: ['@'], sortKey: (item: string) => { if (item.indexOf(':') === -1) { return 'a'; } @@ -410,24 +410,22 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio else { return 'd'; } }, provideResults: (query: string) => Query.suggestions(query) - }, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue }); + }, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue })); if (this.searchBox.getValue()) { this.triggerSearch(); } - this.disposables.push(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService)); - - this.disposables.push(this.searchBox); + this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService)); const _searchChange = new Emitter(); this.onSearchChange = _searchChange.event; - this.searchBox.onInputDidChange(() => { + this._register(this.searchBox.onInputDidChange(() => { this.triggerSearch(); _searchChange.fire(this.searchBox.getValue()); - }, this, this.disposables); + }, this)); - this.searchBox.onShouldFocusResults(() => this.focusListView(), this, this.disposables); + this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this)); this._register(this.onDidChangeVisibility(visible => { if (visible) { @@ -480,6 +478,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL), ...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]), this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL), + ...(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer ? [this.instantiationService.createInstance(InstallLocalExtensionsOnRemoteAction)] : []), new Separator(), this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL), this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL) @@ -614,52 +613,34 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.notificationService.error(err); } - - dispose(): void { - this.disposables = dispose(this.disposables); - super.dispose(); - } } -export class StatusUpdater implements IWorkbenchContribution { +export class StatusUpdater extends Disposable implements IWorkbenchContribution { - private disposables: IDisposable[]; - private badgeHandle: IDisposable; + private readonly badgeHandle = this._register(new MutableDisposable()); constructor( @IActivityService private readonly activityService: IActivityService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService ) { - extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables); + super(); + this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this)); } private onServiceChange(): void { - - dispose(this.badgeHandle); - - if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) { - this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge'); - return; - } + this.badgeHandle.clear(); const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0); if (outdated > 0) { const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n)); - this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge'); + this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge'); } } - - dispose(): void { - this.disposables = dispose(this.disposables); - dispose(this.badgeHandle); - } } export class MaliciousExtensionChecker implements IWorkbenchContribution { - private disposables: IDisposable[]; - constructor( @IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService, @IWindowService private readonly windowService: IWindowService, @@ -704,8 +685,4 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution { }).then(() => undefined); }, err => this.logService.error(err)); } - - dispose(): void { - this.disposables = dispose(this.disposables); - } } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts similarity index 97% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 6dad2fb5808..f9bf9ad4458 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -9,13 +9,14 @@ 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'; import { append, $, toggleClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/electron-browser/extensionsList'; +import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/browser/extensionsList'; import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions'; import { Query } from '../common/extensionQuery'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -27,14 +28,14 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; +import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { WorkbenchPagedList } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { INotificationService, Severity } 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 { distinct, coalesce } from 'vs/base/common/arrays'; -import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; @@ -46,6 +47,7 @@ import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IProductService } from 'vs/platform/product/common/product'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; class ExtensionsViewState extends Disposable implements IExtensionsViewState { @@ -100,8 +102,9 @@ export class ExtensionsListView extends ViewletPanel { @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IProductService protected readonly productService: IProductService, + @IContextKeyService contextKeyService: IContextKeyService, ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService); this.server = options.server; } @@ -848,9 +851,10 @@ export class ServerExtensionsView extends ExtensionsListView { @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, @IProductService productService: IProductService, + @IContextKeyService contextKeyService: IContextKeyService, ) { options.server = server; - super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService); + super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService, contextKeyService); this._register(onDidChangeTitle(title => this.updateTitle(title))); } @@ -864,18 +868,18 @@ export class ServerExtensionsView extends ExtensionsListView { } export class EnabledExtensionsView extends ExtensionsListView { - private readonly enabledExtensionsQuery = '@enabled'; async show(query: string): Promise> { - return (query && query.trim() !== this.enabledExtensionsQuery) ? this.showEmptyModel() : super.show(this.enabledExtensionsQuery); + query = query || '@enabled'; + return ExtensionsListView.isEnabledExtensionsQuery(query) ? super.show(query) : this.showEmptyModel(); } } export class DisabledExtensionsView extends ExtensionsListView { - private readonly disabledExtensionsQuery = '@disabled'; async show(query: string): Promise> { - return (query && query.trim() !== this.disabledExtensionsQuery) ? this.showEmptyModel() : super.show(this.disabledExtensionsQuery); + query = query || '@disabled'; + return ExtensionsListView.isDisabledExtensionsQuery(query) ? super.show(query) : this.showEmptyModel(); } } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts similarity index 77% rename from src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts index c34a342320f..e27cc72e7d1 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts @@ -4,18 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/extensionsWidgets'; -import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState } from '../common/extensions'; +import { Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IExtension, IExtensionsWorkbenchService, IExtensionContainer } from 'vs/workbench/contrib/extensions/common/extensions'; 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/electron-browser/extensionsActions'; +import { extensionButtonProminentBackground, extensionButtonProminentForeground, ExtensionToolTipAction } 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'; @@ -147,17 +145,13 @@ export class TooltipWidget extends ExtensionWidget { constructor( private readonly parent: HTMLElement, - private readonly disabledLabelAction: DisabledLabelAction, + private readonly tooltipAction: ExtensionToolTipAction, 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( - this.disabledLabelAction.onDidChange, - this.reloadAction.onDidChange, + this.tooltipAction.onDidChange, this.recommendationWidget.onDidChangeTooltip, this.labelService.onDidChangeFormatters )(() => this.render())); @@ -176,17 +170,8 @@ export class TooltipWidget extends ExtensionWidget { if (!this.extension) { return ''; } - if (this.reloadAction.enabled) { - return this.reloadAction.tooltip; - } - if (this.disabledLabelAction.label) { - return this.disabledLabelAction.label; - } - 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 locally', "Extension is enabled locally."); + if (this.tooltipAction.tooltip) { + return this.tooltipAction.tooltip; } return this.recommendationWidget.tooltip; } @@ -196,7 +181,7 @@ export class TooltipWidget extends ExtensionWidget { export class RecommendationWidget extends ExtensionWidget { private element?: HTMLElement; - private disposables: IDisposable[] = []; + private readonly disposables = this._register(new DisposableStore()); private _tooltip: string; get tooltip(): string { return this._tooltip; } @@ -227,7 +212,7 @@ export class RecommendationWidget extends ExtensionWidget { this.parent.removeChild(this.element); } this.element = undefined; - this.disposables = dispose(this.disposables); + this.disposables.clear(); } render(): void { @@ -256,8 +241,7 @@ export class RecommendationWidget extends ExtensionWidget { export class RemoteBadgeWidget extends ExtensionWidget { - private remoteBadge: RemoteBadge | null; - private disposables: IDisposable[] = []; + private readonly remoteBadge = this._register(new MutableDisposable()); private element: HTMLElement; @@ -274,30 +258,19 @@ export class RemoteBadgeWidget extends ExtensionWidget { } private clear(): void { - if (this.remoteBadge) { - this.element.removeChild(this.remoteBadge.element); - this.remoteBadge.dispose(); + if (this.remoteBadge.value) { + this.element.removeChild(this.remoteBadge.value.element); } - this.remoteBadge = null; - this.disposables = dispose(this.disposables); + this.remoteBadge.clear(); } 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 = this.instantiationService.createInstance(RemoteBadge, this.tooltip); - append(this.element, this.remoteBadge.element); - } - } - - dispose(): void { - if (this.remoteBadge) { - this.remoteBadge.dispose(); - } - super.dispose(); + this.remoteBadge.value = this.instantiationService.createInstance(RemoteBadge, this.tooltip); + append(this.element, this.remoteBadge.value.element); } } @@ -309,7 +282,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'); @@ -333,8 +306,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 88% rename from src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index c08a6e37c16..7ddf7c7fa70 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'; @@ -14,19 +14,18 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, - InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionManagementServerService, IExtensionManagementServer + InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier } 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'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; -import product from 'vs/platform/product/node/product'; import { ILogService } from 'vs/platform/log/common/log'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -36,6 +35,8 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag 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'; interface IExtensionStateProvider { (extension: Extension): T; @@ -43,21 +44,22 @@ interface IExtensionStateProvider { class Extension implements IExtension { - public enablementState: EnablementState = EnablementState.Enabled; + public enablementState: EnablementState = EnablementState.EnabledGlobally; constructor( - private galleryService: IExtensionGalleryService, private stateProvider: IExtensionStateProvider, public readonly server: IExtensionManagementServer | undefined, public local: ILocalExtension | undefined, public gallery: IGalleryExtension | undefined, - private telemetryService: ITelemetryService, - private logService: ILogService, - private fileService: IFileService + @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, + @ITelemetryService private readonly telemetryService: ITelemetryService, + @ILogService private readonly logService: ILogService, + @IFileService private readonly fileService: IFileService, + @IProductService private readonly productService: IProductService ) { } - get type(): ExtensionType | undefined { - return this.local ? this.local.type : undefined; + get type(): ExtensionType { + return this.local ? this.local.type : ExtensionType.User; } get name(): string { @@ -112,11 +114,11 @@ class Extension implements IExtension { } get url(): string | undefined { - if (!product.extensionsGallery || !this.gallery) { + if (!this.productService.extensionsGallery || !this.gallery) { return undefined; } - return `${product.extensionsGallery.itemUrl}?itemName=${this.publisher}.${this.name}`; + return `${this.productService.extensionsGallery.itemUrl}?itemName=${this.publisher}.${this.name}`; } get iconUrl(): string { @@ -129,7 +131,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; } @@ -146,14 +148,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('../electron-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('../electron-browser/media/language-icon.svg'); + return require.toUrl('./media/language-icon.svg'); } } } - return require.toUrl('../electron-browser/media/defaultIcon.png'); + return require.toUrl('./media/defaultIcon.png'); } get repository(): string | undefined { @@ -317,10 +319,8 @@ class Extensions extends Disposable { private readonly server: IExtensionManagementServer, private readonly stateProvider: IExtensionStateProvider, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @ILogService private readonly logService: ILogService, - @IFileService private readonly fileService: IFileService, - @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService + @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, + @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); this._register(server.extensionManagementService.onInstallExtension(e => this.onInstallExtension(e))); @@ -342,7 +342,7 @@ class Extensions extends Disposable { const installed = await this.server.extensionManagementService.getInstalled(); const byId = index(this.installed, e => e.local ? e.local.identifier.id : e.identifier.id); this.installed = installed.map(local => { - const extension = byId[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, this.server, local, undefined, this.telemetryService, this.logService, this.fileService); + const extension = byId[local.identifier.id] || this.instantiationService.createInstance(Extension, this.stateProvider, this.server, local, undefined); extension.local = local; extension.enablementState = this.extensionEnablementService.getEnablementState(local); return extension; @@ -395,7 +395,7 @@ class Extensions extends Disposable { const { gallery } = event; if (gallery) { const extension = this.installed.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] - || new Extension(this.galleryService, this.stateProvider, this.server, undefined, gallery, this.telemetryService, this.logService, this.fileService); + || this.instantiationService.createInstance(Extension, this.stateProvider, this.server, undefined, gallery); this.installing.push(extension); this._onChange.fire(extension); } @@ -406,7 +406,9 @@ class Extensions extends Disposable { const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] : null; this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing; - let extension: Extension | undefined = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, this.server, local, undefined, this.telemetryService, this.logService, this.fileService) : undefined; + let extension: Extension | undefined = installingExtension ? installingExtension + : (zipPath || local) ? this.instantiationService.createInstance(Extension, this.stateProvider, this.server, local, undefined) + : undefined; if (extension) { if (local) { const installed = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier))[0]; @@ -474,8 +476,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; @@ -496,21 +498,20 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension @IURLService urlService: IURLService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IWindowService private readonly windowService: IWindowService, - @ILogService private readonly logService: ILogService, @IProgressService private readonly progressService: IProgressService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IStorageService private readonly storageService: IStorageService, - @IFileService private readonly fileService: IFileService, - @IModeService private readonly modeService: IModeService + @IModeService private readonly modeService: IModeService, + @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); @@ -535,6 +536,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension this.resetIgnoreAutoUpdateExtensions(); this.eventuallySyncWithGallery(true); }); + + this._register(this.onChange(() => this.updateActivity())); } get local(): IExtension[] { @@ -544,7 +547,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); } @@ -552,7 +558,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); } @@ -561,7 +570,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) { @@ -569,12 +578,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; } @@ -606,7 +615,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension text = text.replace(extensionRegex, (m, ext) => { // Get curated keywords - const lookup = product.extensionKeywords || {}; + const lookup = this.productService.extensionKeywords || {}; const keywords = lookup[ext] || []; // Get mode name @@ -638,7 +647,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(); @@ -649,7 +661,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension if (installed) { return installed; } - const extension = new Extension(this.galleryService, ext => this.getExtensionState(ext), undefined, undefined, gallery, this.telemetryService, this.logService, this.fileService); + const extension = this.instantiationService.createInstance(Extension, ext => this.getExtensionState(ext), undefined, undefined, gallery); if (maliciousExtensionSet.has(extension.identifier.id)) { extension.isMalicious = true; } @@ -674,7 +686,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; @@ -685,7 +697,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 { @@ -755,13 +770,21 @@ 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 { - if (typeof extension === 'string') { + install(extension: URI | IExtension): Promise { + if (extension instanceof URI) { return this.installWithProgress(async () => { - 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]; }); @@ -868,16 +891,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); @@ -892,7 +915,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); @@ -917,7 +940,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 => @@ -941,7 +964,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) { @@ -991,7 +1014,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; @@ -999,11 +1022,26 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension get allowedBadgeProviders(): string[] { if (!this._extensionAllowedBadgeProviders) { - this._extensionAllowedBadgeProviders = (product.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase()); + this._extensionAllowedBadgeProviders = (this.productService.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase()); } return this._extensionAllowedBadgeProviders; } + private _activityCallBack: (() => void) | null = null; + private updateActivity(): void { + if ((this.localExtensions && this.localExtensions.local.some(e => e.state === ExtensionState.Installing || e.state === ExtensionState.Uninstalling)) + || (this.remoteExtensions && this.remoteExtensions.local.some(e => e.state === ExtensionState.Installing || e.state === ExtensionState.Uninstalling))) { + if (!this._activityCallBack) { + this.progressService.withProgress({ location: ProgressLocation.Extensions }, () => new Promise(c => this._activityCallBack = c)); + } + } else { + if (this._activityCallBack) { + this._activityCallBack(); + } + this._activityCallBack = null; + } + } + private onError(err: any): void { if (isPromiseCanceledError(err)) { return; @@ -1043,7 +1081,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return this.windowService.focusWindow() .then(() => this.open(extension)); } - return this.queryGallery({ names: [extensionId], source: 'uri' }, CancellationToken.None).then(result => { if (result.total < 1) { return Promise.resolve(null); @@ -1052,17 +1089,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension const extension = result.firstPage[0]; return this.windowService.focusWindow().then(() => { - return this.open(extension).then(() => { - this.notificationService.prompt( - Severity.Info, - nls.localize('installConfirmation', "Would you like to install the '{0}' extension?", extension.displayName, extension.publisher), - [{ - label: nls.localize('install', "Install"), - run: () => this.install(extension).then(undefined, error => this.onError(error)) - }], - { sticky: true } - ); - }); + return this.open(extension); }); }); }).then(undefined, error => this.onError(error)); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/clear-dark.svg b/src/vs/workbench/contrib/extensions/browser/media/clear-dark.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/clear-dark.svg rename to src/vs/workbench/contrib/extensions/browser/media/clear-dark.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/clear-hc.svg b/src/vs/workbench/contrib/extensions/browser/media/clear-hc.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/clear-hc.svg rename to src/vs/workbench/contrib/extensions/browser/media/clear-hc.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/clear-inverse.svg b/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/clear-inverse.svg rename to src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/clear-light.svg b/src/vs/workbench/contrib/extensions/browser/media/clear-light.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/clear-light.svg rename to src/vs/workbench/contrib/extensions/browser/media/clear-light.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/configure-dark.svg b/src/vs/workbench/contrib/extensions/browser/media/configure-dark.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/configure-dark.svg rename to src/vs/workbench/contrib/extensions/browser/media/configure-dark.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/configure-hc.svg b/src/vs/workbench/contrib/extensions/browser/media/configure-hc.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/configure-hc.svg rename to src/vs/workbench/contrib/extensions/browser/media/configure-hc.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/configure-light.svg b/src/vs/workbench/contrib/extensions/browser/media/configure-light.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/configure-light.svg rename to src/vs/workbench/contrib/extensions/browser/media/configure-light.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/defaultIcon.png b/src/vs/workbench/contrib/extensions/browser/media/defaultIcon.png similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/defaultIcon.png rename to src/vs/workbench/contrib/extensions/browser/media/defaultIcon.png diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionActions.css diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/extensionEditor.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensions-activity-bar.svg b/src/vs/workbench/contrib/extensions/browser/media/extensions-activity-bar.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/extensions-activity-bar.svg rename to src/vs/workbench/contrib/extensions/browser/media/extensions-activity-bar.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensions.css b/src/vs/workbench/contrib/extensions/browser/media/extensions.css similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/extensions.css rename to src/vs/workbench/contrib/extensions/browser/media/extensions.css diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/extensionsViewlet.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionsWidgets.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/extensionsWidgets.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/language-icon.svg b/src/vs/workbench/contrib/extensions/browser/media/language-icon.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/language-icon.svg rename to src/vs/workbench/contrib/extensions/browser/media/language-icon.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/loading.svg b/src/vs/workbench/contrib/extensions/browser/media/loading.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/loading.svg rename to src/vs/workbench/contrib/extensions/browser/media/loading.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/markdown.css b/src/vs/workbench/contrib/extensions/browser/media/markdown.css similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/markdown.css rename to src/vs/workbench/contrib/extensions/browser/media/markdown.css diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/profile-start-dark.svg b/src/vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/profile-start-dark.svg rename to src/vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/profile-start-light.svg b/src/vs/workbench/contrib/extensions/browser/media/profile-start-light.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/profile-start-light.svg rename to src/vs/workbench/contrib/extensions/browser/media/profile-start-light.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/profile-stop-dark.svg b/src/vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/profile-stop-dark.svg rename to src/vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/profile-stop-light.svg b/src/vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/profile-stop-light.svg rename to src/vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/save-dark.svg b/src/vs/workbench/contrib/extensions/browser/media/save-dark.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/save-dark.svg rename to src/vs/workbench/contrib/extensions/browser/media/save-dark.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/save-light.svg b/src/vs/workbench/contrib/extensions/browser/media/save-light.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/save-light.svg rename to src/vs/workbench/contrib/extensions/browser/media/save-light.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/star-empty.svg b/src/vs/workbench/contrib/extensions/browser/media/star-empty.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/star-empty.svg rename to src/vs/workbench/contrib/extensions/browser/media/star-empty.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/star-full.svg b/src/vs/workbench/contrib/extensions/browser/media/star-full.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/star-full.svg rename to src/vs/workbench/contrib/extensions/browser/media/star-full.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/star-half.svg b/src/vs/workbench/contrib/extensions/browser/media/star-half.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/star-half.svg rename to src/vs/workbench/contrib/extensions/browser/media/star-half.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/star-small.svg b/src/vs/workbench/contrib/extensions/browser/media/star-small.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/star-small.svg rename to src/vs/workbench/contrib/extensions/browser/media/star-small.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/start-dark.svg b/src/vs/workbench/contrib/extensions/browser/media/start-dark.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/start-dark.svg rename to src/vs/workbench/contrib/extensions/browser/media/start-dark.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/start-light.svg b/src/vs/workbench/contrib/extensions/browser/media/start-light.svg similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/start-light.svg rename to src/vs/workbench/contrib/extensions/browser/media/start-light.svg diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/theme-icon.png b/src/vs/workbench/contrib/extensions/browser/media/theme-icon.png similarity index 100% rename from src/vs/workbench/contrib/extensions/electron-browser/media/theme-icon.png rename to src/vs/workbench/contrib/extensions/browser/media/theme-icon.png diff --git a/src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.ts b/src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.ts new file mode 100644 index 00000000000..19e4a47c99c --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { localize } from 'vs/nls'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { InstallLocalExtensionsOnRemoteAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; + +export class RemoteExtensionsInstaller extends Disposable implements IWorkbenchContribution { + + constructor( + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @ILabelService labelService: ILabelService, + @IInstantiationService instantiationService: IInstantiationService + ) { + super(); + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + const installLocalExtensionsOnRemoteAction = instantiationService.createInstance(InstallLocalExtensionsOnRemoteAction); + CommandsRegistry.registerCommand('workbench.extensions.installLocalExtensions', () => installLocalExtensionsOnRemoteAction.run()); + let disposable = Disposable.None; + const appendMenuItem = () => { + disposable.dispose(); + disposable = MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: 'workbench.extensions.installLocalExtensions', + category: localize('extensions', "Extensions"), + title: installLocalExtensionsOnRemoteAction.label + } + }); + }; + appendMenuItem(); + this._register(labelService.onDidChangeFormatters(e => appendMenuItem())); + this._register(toDisposable(() => disposable.dispose())); + } + } + +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/common/extensionQuery.ts b/src/vs/workbench/contrib/extensions/common/extensionQuery.ts index 445e23db188..6c5a2505331 100644 --- a/src/vs/workbench/contrib/extensions/common/extensionQuery.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionQuery.ts @@ -12,12 +12,13 @@ export class Query { } static suggestions(query: string): string[] { - const commands = ['installed', 'outdated', 'enabled', 'disabled', 'builtin', 'recommended', 'sort', 'category', 'tag', 'ext']; + const commands = ['installed', 'outdated', 'enabled', 'disabled', 'builtin', 'recommended', 'sort', 'category', 'tag', 'ext', 'id']; const subcommands = { 'sort': ['installs', 'rating', 'name'], 'category': ['"programming languages"', 'snippets', 'linters', 'themes', 'debuggers', 'formatters', 'keymaps', '"scm providers"', 'other', '"extension packs"', '"language packs"'], 'tag': [''], - 'ext': [''] + 'ext': [''], + 'id': [''] }; let queryContains = (substr: string) => query.indexOf(substr) > -1; @@ -77,4 +78,4 @@ export class Query { equals(other: Query): boolean { return this.value === other.value && this.sortBy === other.sortBy; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index e0e9a941d9c..33e46eecf82 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); @@ -32,7 +34,7 @@ export const enum ExtensionState { } export interface IExtension { - readonly type?: ExtensionType; + readonly type: ExtensionType; readonly state: ExtensionState; readonly name: string; readonly displayName: string; @@ -81,7 +83,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 edf2a12d6fd..ea48be50fa0 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/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index 65cbc3a44b1..283c3406d8f 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; @@ -37,7 +37,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio private _state: ProfileSessionState; private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined; - private profilingStatusBarIndicatorLabelUpdater: IDisposable | undefined; + private readonly profilingStatusBarIndicatorLabelUpdater = this._register(new MutableDisposable()); public get state() { return this._state; } public get lastProfile() { return this._profile; } @@ -77,10 +77,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio } private updateProfilingStatusBarIndicator(visible: boolean): void { - if (this.profilingStatusBarIndicatorLabelUpdater) { - this.profilingStatusBarIndicatorLabelUpdater.dispose(); - this.profilingStatusBarIndicatorLabelUpdater = undefined; - } + this.profilingStatusBarIndicatorLabelUpdater.clear(); if (visible) { const indicator: IStatusbarEntry = { @@ -95,7 +92,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio this.profilingStatusBarIndicator.update({ ...indicator, text: nls.localize('profilingExtensionHostTime', "$(sync~spin) Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), }); } }, 1000); - this.profilingStatusBarIndicatorLabelUpdater = toDisposable(() => clearInterval(handle)); + this.profilingStatusBarIndicatorLabelUpdater.value = toDisposable(() => clearInterval(handle)); if (!this.profilingStatusBarIndicator) { this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, 'status.profiler', nls.localize('status.profiler', "Extension Profiler"), StatusbarAlignment.RIGHT); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index f192f1c16d9..b64e6d66977 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -4,21 +4,19 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { join } from 'vs/base/common/path'; +import { join, basename } from 'vs/base/common/path'; import { forEach } from 'vs/base/common/collections'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +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'; import product from 'vs/platform/product/node/product'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ShowRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction, InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; +import { ShowRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction, InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import Severity from 'vs/base/common/severity'; import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace, IWorkspaceFoldersChangeEvent, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IFileService } from 'vs/platform/files/common/files'; @@ -32,8 +30,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { guessMimeTypes, MIME_UNKNOWN } from 'vs/base/common/mime'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { getHashedRemotesFromUri } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { asJson } from 'vs/base/node/request'; +import { IRequestService, asJson } from 'vs/platform/request/common/request'; import { isNumber } from 'vs/base/common/types'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -41,11 +38,13 @@ import { Emitter, Event } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { extname } from 'vs/base/common/resources'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IExeBasedExtensionTip } from 'vs/platform/product/common/product'; +import { timeout } from 'vs/base/common/async'; const milliSecondsInADay = 1000 * 60 * 60 * 24; const choiceNever = localize('neverShowAgain', "Don't Show Again"); @@ -74,7 +73,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe _serviceBrand: any; private _fileBasedRecommendations: { [id: string]: { recommendedTime: number, sources: ExtensionRecommendationSource[] }; } = Object.create(null); - private _exeBasedRecommendations: { [id: string]: string; } = Object.create(null); + private _exeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); + private _importantExeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); private _availableRecommendations: { [pattern: string]: string[] } = Object.create(null); private _allWorkspaceRecommendedExtensions: IExtensionRecommendation[] = []; private _dynamicWorkspaceRecommendations: string[] = []; @@ -83,7 +83,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private _globallyIgnoredRecommendations: string[] = []; private _workspaceIgnoredRecommendations: string[] = []; private _extensionsRecommendationsUrl: string; - private _disposables: IDisposable[] = []; public loadWorkspaceConfigPromise: Promise; private proactiveRecommendationsFetched: boolean = false; @@ -135,7 +134,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe this.loadWorkspaceConfigPromise = this.getWorkspaceRecommendations().then(() => { this.promptWorkspaceRecommendations(); - this._modelService.onModelAdded(this.promptFiletypeBasedRecommendations, this, this._disposables); + this._register(this._modelService.onModelAdded(this.promptFiletypeBasedRecommendations, this)); this._modelService.getModels().forEach(model => this.promptFiletypeBasedRecommendations(model)); }); @@ -191,7 +190,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe forEach(this._exeBasedRecommendations, entry => output[entry.key.toLowerCase()] = { reasonId: ExtensionRecommendationReason.Executable, - reasonText: localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value) + reasonText: localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value.friendlyName) }); forEach(this._fileBasedRecommendations, entry => output[entry.key.toLowerCase()] = { @@ -500,6 +499,100 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe //#endregion + //#region important exe based extension + + private async promptForImportantExeBasedExtension(): Promise { + + const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + const config = this.configurationService.getValue(ConfigurationKey); + + if (config.ignoreRecommendations + || config.showRecommendationsOnlyOnDemand + || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { + return false; + } + + const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); + let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); + recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + if (recommendationsToSuggest.length === 0) { + return false; + } + + const id = recommendationsToSuggest[0]; + const tip = this._importantExeBasedRecommendations[id]; + const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!)); + + this.notificationService.prompt(Severity.Info, message, + [{ + label: localize('install', 'Install'), + run: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'install', extensionId: name }); + this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run(); + } + }, { + label: localize('showRecommendations', "Show Recommendations"), + run: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'show', extensionId: name }); + + const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + recommendationsAction.run(); + recommendationsAction.dispose(); + } + }, { + label: choiceNever, + isSecondary: true, + run: () => { + this.addToImportantRecommendationsIgnore(id); + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name }); + this.notificationService.prompt( + Severity.Info, + localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), + [{ + label: localize('ignoreAll', "Yes, Ignore All"), + run: () => this.setIgnoreRecommendationsConfig(true) + }, { + label: localize('no', "No"), + run: () => this.setIgnoreRecommendationsConfig(false) + }] + ); + } + }], + { + sticky: true, + onCancel: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); + } + } + ); + + return true; + } + //#region fileBasedRecommendations getFileBasedRecommendations(): IExtensionRecommendation[] { @@ -601,7 +694,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe const now = Date.now(); forEach(this._availableRecommendations, entry => { let { key: pattern, value: ids } = entry; - if (match(pattern, model.uri.path)) { + if (match(pattern, model.uri.toString())) { for (let id of ids) { if (caseInsensitiveGet(product.extensionImportantTips, id)) { recommendationsToSuggest.push(id); @@ -650,21 +743,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } private async promptRecommendedExtensionForFileType(recommendationsToSuggest: string[], installed: ILocalExtension[]): Promise { - const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); - recommendationsToSuggest = recommendationsToSuggest.filter(id => { - if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { - return false; - } - if (!this.isExtensionAllowedToBeRecommended(id)) { - return false; - } - if (installedExtensionsIds.has(id.toLowerCase())) { - return false; - } - return true; - }); + recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); if (recommendationsToSuggest.length === 0) { return false; } @@ -674,22 +754,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (!entry) { return false; } - const name = entry['name']; - + const name = entry.name; let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); - // Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364 - if (id === 'vscjava.vscode-java-pack') { + if (entry.isExtensionPack) { message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name); } - const setIgnoreRecommendationsConfig = (configVal: boolean) => { - this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); - if (configVal) { - const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; - this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); - } - }; - this.notificationService.prompt(Severity.Info, message, [{ label: localize('install', 'Install'), @@ -722,12 +792,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe label: choiceNever, isSecondary: true, run: () => { - importantRecommendationsIgnoreList.push(id); - this.storageService.store( - 'extensionsAssistant/importantRecommendationsIgnore', - JSON.stringify(importantRecommendationsIgnoreList), - StorageScope.GLOBAL - ); + this.addToImportantRecommendationsIgnore(id); /* __GDPR__ "extensionRecommendations:popup" : { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -740,10 +805,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), [{ label: localize('ignoreAll', "Yes, Ignore All"), - run: () => setIgnoreRecommendationsConfig(true) + run: () => this.setIgnoreRecommendationsConfig(true) }, { label: localize('no', "No"), - run: () => setIgnoreRecommendationsConfig(false) + run: () => this.setIgnoreRecommendationsConfig(false) }] ); } @@ -835,6 +900,42 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe ); } + private filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] { + + const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); + const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); + return recommendationsToSuggest.filter(id => { + if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { + return false; + } + if (!this.isExtensionAllowedToBeRecommended(id)) { + return false; + } + if (installedExtensionsIds.has(id.toLowerCase())) { + return false; + } + return true; + }); + } + + private addToImportantRecommendationsIgnore(id: string) { + const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); + importantRecommendationsIgnoreList.push(id); + this.storageService.store( + 'extensionsAssistant/importantRecommendationsIgnore', + JSON.stringify(importantRecommendationsIgnoreList), + StorageScope.GLOBAL + ); + } + + private setIgnoreRecommendationsConfig(configVal: boolean) { + this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); + if (configVal) { + const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); + } + } + //#endregion //#region otherRecommendations @@ -861,18 +962,18 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } private fetchProactiveRecommendations(calledDuringStartup?: boolean): Promise { - let fetchPromise = Promise.resolve(undefined); + let fetchPromise = Promise.resolve(undefined); if (!this.proactiveRecommendationsFetched) { this.proactiveRecommendationsFetched = true; - // Executable based recommendations carry out a lot of file stats, so run them after 10 secs - // So that the startup is not affected + // Executable based recommendations carry out a lot of file stats, delay the resolution so that the startup is not affected + // 10 sec for regular extensions + // 3 secs for important - fetchPromise = new Promise((c, e) => { - setTimeout(() => { - Promise.all([this.fetchExecutableRecommendations(), this.fetchDynamicWorkspaceRecommendations()]).then(() => c(undefined)); - }, calledDuringStartup ? 10000 : 0); - }); + const importantExeBasedRecommendations = timeout(calledDuringStartup ? 3000 : 0).then(_ => this.fetchExecutableRecommendations(true)); + importantExeBasedRecommendations.then(_ => this.promptForImportantExeBasedExtension()); + + fetchPromise = timeout(calledDuringStartup ? 10000 : 0).then(_ => Promise.all([this.fetchDynamicWorkspaceRecommendations(), this.fetchExecutableRecommendations(false), importantExeBasedRecommendations])); } return fetchPromise; @@ -881,20 +982,22 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe /** * If user has any of the tools listed in product.exeBasedExtensionTips, fetch corresponding recommendations */ - private fetchExecutableRecommendations(): Promise { + private fetchExecutableRecommendations(important: boolean): Promise { const homeDir = os.homedir(); let foundExecutables: Set = new Set(); - let findExecutable = (exeName: string, path: string) => { + let findExecutable = (exeName: string, tip: IExeBasedExtensionTip, path: string) => { return pfs.fileExists(path).then(exists => { if (exists && !foundExecutables.has(exeName)) { foundExecutables.add(exeName); - (product.exeBasedExtensionTips[exeName]['recommendations'] || []) - .forEach(extensionId => { - if (product.exeBasedExtensionTips[exeName]['friendlyName']) { - this._exeBasedRecommendations[extensionId.toLowerCase()] = product.exeBasedExtensionTips[exeName]['friendlyName']; + (tip['recommendations'] || []).forEach(extensionId => { + if (tip.friendlyName) { + if (important) { + this._importantExeBasedRecommendations[extensionId.toLowerCase()] = tip; } - }); + this._exeBasedRecommendations[extensionId.toLowerCase()] = tip; + } + }); } }); }; @@ -905,8 +1008,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) { return; } - - let exeName = entry.key; + if (important !== !!entry.value.important) { + return; + } + const exeName = entry.key; if (process.platform === 'win32') { let windowsPath = entry.value['windowsPath']; if (!windowsPath || typeof windowsPath !== 'string') { @@ -915,11 +1020,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe windowsPath = windowsPath.replace('%USERPROFILE%', process.env['USERPROFILE']!) .replace('%ProgramFiles(x86)%', process.env['ProgramFiles(x86)']!) .replace('%ProgramFiles%', process.env['ProgramFiles']!) - .replace('%APPDATA%', process.env['APPDATA']!); - promises.push(findExecutable(exeName, windowsPath)); + .replace('%APPDATA%', process.env['APPDATA']!) + .replace('%WINDIR%', process.env['WINDIR']!); + promises.push(findExecutable(exeName, entry.value, windowsPath)); } else { - promises.push(findExecutable(exeName, join('/usr/local/bin', exeName))); - promises.push(findExecutable(exeName, join(homeDir, exeName))); + promises.push(findExecutable(exeName, entry.value, join('/usr/local/bin', exeName))); + promises.push(findExecutable(exeName, entry.value, join(homeDir, exeName))); } }); @@ -1035,8 +1141,4 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private isExtensionAllowedToBeRecommended(id: string): boolean { return this._allIgnoredRecommendations.indexOf(id.toLowerCase()) === -1; } - - dispose() { - this._disposables = dispose(this._disposables); - } } 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 77643b4b45f..643c6e1b456 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -3,104 +3,33 @@ * Licensed under the MIT License. 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 { 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'; -import { VIEWLET_ID, IExtensionsWorkbenchService } 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/electron-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/electron-browser/extensionEditor'; -import { StatusUpdater, ExtensionsViewlet, MaliciousExtensionChecker, ExtensionsViewletViewsContribution } from 'vs/workbench/contrib/extensions/electron-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/electron-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 @@ -125,150 +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', - 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 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 - } - } - }); - -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); @@ -290,46 +81,6 @@ CommandsRegistry.registerCommand(SaveExtensionHostProfileAction.ID, (accessor: S instantiationService.createInstance(SaveExtensionHostProfileAction, SaveExtensionHostProfileAction.ID, SaveExtensionHostProfileAction.LABEL).run(); }); -// 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 -}); - // Running extensions MenuRegistry.appendMenuItem(MenuId.EditorTitle, { @@ -337,8 +88,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: DebugExtensionHostAction.ID, title: DebugExtensionHostAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/start-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/start-light.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/start-dark.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/start-light.svg`)), } }, group: 'navigation', @@ -350,8 +101,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: StartExtensionHostProfileAction.ID, title: StartExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/profile-start-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/profile-start-light.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-start-light.svg`)), } }, group: 'navigation', @@ -363,8 +114,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: StopExtensionHostProfileAction.ID, title: StopExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/profile-stop-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/profile-stop-light.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg`)), } }, group: 'navigation', @@ -376,85 +127,11 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: SaveExtensionHostProfileAction.ID, title: SaveExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/save-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/electron-browser/media/save-light.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/save-dark.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/save-light.svg`)), }, precondition: CONTEXT_EXTENSION_HOST_PROFILE_RECORDED }, 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/extensionsSlowActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts index fece37e6a35..3b81b03291c 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts @@ -11,9 +11,8 @@ import { URI } from 'vs/base/common/uri'; import { IExtensionHostProfile } from 'vs/workbench/services/extensions/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { localize } from 'vs/nls'; -import { IRequestService } from 'vs/platform/request/node/request'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { asText } from 'vs/base/node/request'; +import { IRequestService, asText } from 'vs/platform/request/common/request'; import { join } from 'vs/base/common/path'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index d5666b2f5f8..1cc01b85802 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'; @@ -405,7 +405,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { multipleSelectionSupport: false, setRowLineHeight: false, horizontalScrolling: false - }) as WorkbenchList; + }); this._list.splice(0, this._list.length, this._elements || undefined); @@ -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 9d1919ae5e5..2334ecebeec 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 @@ -7,20 +7,21 @@ import * as assert from 'assert'; 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/electron-browser/extensionsActions'; -import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService'; +import * as ExtensionsActions from 'vs/workbench/contrib/extensions/browser/extensionsActions'; +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'; import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IURLService } from 'vs/platform/url/common/url'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { Emitter } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { IPager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -39,8 +40,13 @@ 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'; +import { Schemas } from 'vs/base/common/network'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IProgressService } from 'vs/platform/progress/common/progress'; +import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; suite('ExtensionsActions Test', () => { @@ -52,7 +58,7 @@ suite('ExtensionsActions Test', () => { didUninstallEvent: Emitter; - suiteSetup(() => { + setup(async () => { installEvent = new Emitter(); didInstallEvent = new Emitter(); uninstallEvent = new Emitter(); @@ -65,6 +71,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(IConfigurationService, new TestConfigurationService()); + instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); instantiationService.stub(ISharedProcessService, TestSharedProcessService); @@ -79,7 +86,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) { } @@ -90,9 +97,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService)); instantiationService.stub(IURLService, URLService); - }); - setup(async () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); @@ -601,7 +606,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 +621,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 +636,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 +670,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 +685,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 +700,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 +734,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 +749,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 +810,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 +825,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 +858,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 +873,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 +918,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 +933,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]); @@ -1061,37 +1066,39 @@ suite('ExtensionsActions Test', () => { assert.ok(!testObject.enabled); }); - test('Test ReloadAction when extension state is installing', () => { + test('Test ReloadAction when extension state is installing', async () => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); const gallery = aGalleryExtension('a'); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); - return workbenchService.queryGallery(CancellationToken.None) - .then((paged) => { - testObject.extension = paged.firstPage[0]; - installEvent.fire({ identifier: gallery.identifier, gallery }); + const paged = await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = paged.firstPage[0]; + installEvent.fire({ identifier: gallery.identifier, gallery }); - assert.ok(!testObject.enabled); - }); + assert.ok(!testObject.enabled); }); - test('Test ReloadAction when extension state is uninstalling', () => { + test('Test ReloadAction when extension state is uninstalling', async () => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return instantiationService.get(IExtensionsWorkbenchService).queryLocal() - .then(extensions => { - testObject.extension = extensions[0]; - uninstallEvent.fire(local.identifier); - assert.ok(!testObject.enabled); - }); + const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal(); + testObject.extension = extensions[0]; + uninstallEvent.fire(local.identifier); + assert.ok(!testObject.enabled); }); test('Test ReloadAction when extension is newly installed', async () => { - instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]); + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + const runningExtensions = [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]; + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve(runningExtensions), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const gallery = aGalleryExtension('a'); @@ -1101,34 +1108,50 @@ suite('ExtensionsActions Test', () => { testObject.extension = paged.firstPage[0]; assert.ok(!testObject.enabled); - return new Promise(c => { - testObject.onDidChange(() => { - if (testObject.enabled && testObject.tooltip === 'Please reload Visual Studio Code to enable this extension.') { - c(); - } - }); - installEvent.fire({ identifier: gallery.identifier, gallery }); - didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) }); - }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) }); + assert.ok(testObject.enabled); + assert.equal(testObject.tooltip, 'Please reload Visual Studio Code to enable this extension.'); }); - test('Test ReloadAction when extension is installed and uninstalled', () => { + test('Test ReloadAction when extension is newly installed and reload is not required', async () => { + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + const runningExtensions = [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]; + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve(runningExtensions), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => true + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None); + testObject.extension = paged.firstPage[0]; + assert.ok(!testObject.enabled); + + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) }); + assert.ok(!testObject.enabled); + }); + + test('Test ReloadAction when extension is installed and uninstalled', async () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const gallery = aGalleryExtension('a'); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); - return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None) - .then((paged) => { - testObject.extension = paged.firstPage[0]; - const identifier = gallery.identifier; - installEvent.fire({ identifier, gallery }); - didInstallEvent.fire({ identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, { identifier }) }); - uninstallEvent.fire(identifier); - didUninstallEvent.fire({ identifier }); + const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None); - assert.ok(!testObject.enabled); - }); + testObject.extension = paged.firstPage[0]; + const identifier = gallery.identifier; + installEvent.fire({ identifier, gallery }); + didInstallEvent.fire({ identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, { identifier }) }); + uninstallEvent.fire(identifier); + didUninstallEvent.fire({ identifier }); + + assert.ok(!testObject.enabled); }); test('Test ReloadAction when extension is uninstalled', async () => { @@ -1140,36 +1163,49 @@ suite('ExtensionsActions Test', () => { const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal(); testObject.extension = extensions[0]; - return new Promise(c => { - testObject.onDidChange(() => { - if (testObject.enabled && testObject.tooltip === 'Please reload Visual Studio Code to complete the uninstallation of this extension.') { - c(); - } - }); - uninstallEvent.fire(local.identifier); - didUninstallEvent.fire({ identifier: local.identifier }); - }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); + assert.ok(testObject.enabled); + assert.equal(testObject.tooltip, 'Please reload Visual Studio Code to complete the uninstallation of this extension.'); }); - test('Test ReloadAction when extension is uninstalled and installed', () => { + test('Test ReloadAction when extension is uninstalled and can be removed', async () => { + const local = aLocalExtension('a'); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([ExtensionsActions.toExtensionDescription(local)]), + onDidChangeExtensions: new Emitter().event, + canRemoveExtension: (extension) => true, + canAddExtension: (extension) => true + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal(); + testObject.extension = extensions[0]; + + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); + assert.ok(!testObject.enabled); + }); + + test('Test ReloadAction when extension is uninstalled and installed', async () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return instantiationService.get(IExtensionsWorkbenchService).queryLocal() - .then(extensions => { - testObject.extension = extensions[0]; - uninstallEvent.fire(local.identifier); - didUninstallEvent.fire({ identifier: local.identifier }); + const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal(); - const gallery = aGalleryExtension('a'); - const identifier = gallery.identifier; - installEvent.fire({ identifier, gallery }); - didInstallEvent.fire({ identifier, gallery, operation: InstallOperation.Install, local }); + testObject.extension = extensions[0]; + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); - assert.ok(!testObject.enabled); - }); + const gallery = aGalleryExtension('a'); + const identifier = gallery.identifier; + installEvent.fire({ identifier, gallery }); + didInstallEvent.fire({ identifier, gallery, operation: InstallOperation.Install, local }); + + assert.ok(!testObject.enabled); }); test('Test ReloadAction when extension is updated while running', async () => { @@ -1194,128 +1230,103 @@ suite('ExtensionsActions Test', () => { }); }); - test('Test ReloadAction when extension is updated when not running', () => { + test('Test ReloadAction when extension is updated when not running', async () => { 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) - .then(() => { - const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); - instantiationService.createInstance(ExtensionContainers, [testObject]); - const workbenchService = instantiationService.get(IExtensionsWorkbenchService); - instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return workbenchService.queryLocal() - .then(extensions => { - testObject.extension = extensions[0]; + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const extensions = await workbenchService.queryLocal(); + testObject.extension = extensions[0]; - 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.Update, local: aLocalExtension('a', gallery, gallery) }); + 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.Update, local: aLocalExtension('a', gallery, gallery) }); - assert.ok(!testObject.enabled); - }); - }); + assert.ok(!testObject.enabled); }); - test('Test ReloadAction when extension is disabled when running', () => { + test('Test ReloadAction when extension is disabled when running', async () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return workbenchService.queryLocal().then(extensions => { - testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Disabled) - .then(() => testObject.update()) - .then(() => { - assert.ok(testObject.enabled); - assert.equal('Please reload Visual Studio Code to disable this extension.', testObject.tooltip); - }); - }); + const extensions = await workbenchService.queryLocal(); + testObject.extension = extensions[0]; + await workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally); + await testObject.update(); + + assert.ok(testObject.enabled); + assert.equal('Please reload Visual Studio Code to disable this extension.', testObject.tooltip); }); - test('Test ReloadAction when extension enablement is toggled when running', () => { + test('Test ReloadAction when extension enablement is toggled when running', async () => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return workbenchService.queryLocal(). - then(extensions => { - testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Disabled) - .then(() => workbenchService.setEnablement(extensions[0], EnablementState.Enabled)) - .then(() => assert.ok(!testObject.enabled)); - }); + const extensions = await workbenchService.queryLocal(); + testObject.extension = extensions[0]; + await workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally); + await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally); + assert.ok(!testObject.enabled); }); - test('Test ReloadAction when extension is enabled when not running', () => { + test('Test ReloadAction when extension is enabled when not running', async () => { 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) - .then(() => { - const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); - instantiationService.createInstance(ExtensionContainers, [testObject]); - const workbenchService = instantiationService.get(IExtensionsWorkbenchService); - instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return workbenchService.queryLocal() - .then(extensions => { - testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Enabled) - .then(() => testObject.update()) - .then(() => { - assert.ok(testObject.enabled); - assert.equal('Please reload Visual Studio Code to enable this extension.', testObject.tooltip); - }); - }); - }); + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const extensions = await workbenchService.queryLocal(); + testObject.extension = extensions[0]; + await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally); + await testObject.update(); + assert.ok(testObject.enabled); + assert.equal('Please reload Visual Studio Code to enable this extension.', testObject.tooltip); }); - test('Test ReloadAction when extension enablement is toggled when not running', () => { + test('Test ReloadAction when extension enablement is toggled when not running', async () => { 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) - .then(() => { - const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); - instantiationService.createInstance(ExtensionContainers, [testObject]); - const workbenchService = instantiationService.get(IExtensionsWorkbenchService); - instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return workbenchService.queryLocal() - .then(extensions => { - testObject.extension = extensions[0]; - return workbenchService.setEnablement(extensions[0], EnablementState.Enabled) - .then(() => workbenchService.setEnablement(extensions[0], EnablementState.Disabled)) - .then(() => assert.ok(!testObject.enabled)); - }); - }); + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const extensions = await workbenchService.queryLocal(); + testObject.extension = extensions[0]; + await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally); + await workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally); + assert.ok(!testObject.enabled); }); - test('Test ReloadAction when extension is updated when not running and enabled', () => { + test('Test ReloadAction when extension is updated when not running and enabled', async () => { 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) - .then(() => { - const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); - instantiationService.createInstance(ExtensionContainers, [testObject]); - const workbenchService = instantiationService.get(IExtensionsWorkbenchService); - instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - return workbenchService.queryLocal() - .then(extensions => { - testObject.extension = extensions[0]; + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const extensions = await workbenchService.queryLocal(); + testObject.extension = extensions[0]; - 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) - .then(() => testObject.update()) - .then(() => { - assert.ok(testObject.enabled); - assert.equal('Please reload Visual Studio Code to enable this extension.', testObject.tooltip); - }); - - }); - }); + 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) }); + await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally); + await testObject.update(); + assert.ok(testObject.enabled); + assert.equal('Please reload Visual Studio Code to enable this extension.', testObject.tooltip); }); test('Test ReloadAction when a localization extension is newly installed', async () => { @@ -1350,6 +1361,854 @@ suite('ExtensionsActions Test', () => { assert.ok(!testObject.enabled); }); + test('Test ReloadAction when extension is not installed but extension from different server is installed and running', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a') }); + const remoteExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + const runningExtensions = [ExtensionsActions.toExtensionDescription(remoteExtension)]; + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve(runningExtensions), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test ReloadAction when extension is uninstalled but extension from different server is installed and running', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a') }); + const remoteExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const localExtensionManagementService = createExtensionManagementService([localExtension]); + const uninstallEvent = new Emitter(); + const onDidUninstallEvent = new Emitter<{ identifier: IExtensionIdentifier }>(); + localExtensionManagementService.onUninstallExtension = uninstallEvent.event; + localExtensionManagementService.onDidUninstallExtension = onDidUninstallEvent.event; + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + const runningExtensions = [ExtensionsActions.toExtensionDescription(remoteExtension)]; + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve(runningExtensions), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + + uninstallEvent.fire(localExtension.identifier); + didUninstallEvent.fire({ identifier: localExtension.identifier }); + + assert.ok(!testObject.enabled); + }); + + test('Test ReloadAction when workspace extension is disabled on local server and installed in remote server', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const remoteExtensionManagementService = createExtensionManagementService([]); + const onDidInstallEvent = new Emitter(); + remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const localExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a') }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), remoteExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([]), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + + const remoteExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + onDidInstallEvent.fire({ identifier: remoteExtension.identifier, local: remoteExtension, operation: InstallOperation.Install }); + + assert.ok(testObject.enabled); + assert.equal(testObject.tooltip, 'Please reload Visual Studio Code to enable this extension.'); + }); + + test('Test ReloadAction when ui extension is disabled on remote server and installed in local server', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtensionManagementService = createExtensionManagementService([]); + const onDidInstallEvent = new Emitter(); + localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const remoteExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([]), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + + const localExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file('pub.a') }); + onDidInstallEvent.fire({ identifier: localExtension.identifier, local: localExtension, operation: InstallOperation.Install }); + + assert.ok(testObject.enabled); + assert.equal(testObject.tooltip, 'Please reload Visual Studio Code to enable this extension.'); + }); + + test('Test remote install action is enabled for local workspace extension', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + }); + + test('Test remote install action when installing local workspace extension', async () => { + // multi server setup + const remoteExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + remoteExtensionManagementService.onInstallExtension = onInstallExtension.event; + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), remoteExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const gallery = aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + + onInstallExtension.fire({ identifier: localWorkspaceExtension.identifier, gallery }); + assert.ok(testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); + }); + + test('Test remote install action when installing local workspace extension is finished', async () => { + // multi server setup + const remoteExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + remoteExtensionManagementService.onInstallExtension = onInstallExtension.event; + const onDidInstallEvent = new Emitter(); + remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), remoteExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const gallery = aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + + onInstallExtension.fire({ identifier: localWorkspaceExtension.identifier, gallery }); + assert.ok(testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); + + const installedExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + onDidInstallEvent.fire({ identifier: installedExtension.identifier, local: installedExtension, operation: InstallOperation.Install }); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is enabled for disabled local workspace extension', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + await instantiationService.get(IExtensionEnablementService).setEnablement([localWorkspaceExtension], EnablementState.DisabledGlobally); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + }); + + test('Test remote install action is disabled when extension is not set', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled for extension which is not installed', async () => { + // multi server setup + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const pager = await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = pager.firstPage[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled for local workspace extension which is disabled in env', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IWorkbenchEnvironmentService, { disableExtensions: true } as IWorkbenchEnvironmentService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled when remote server is not available', async () => { + // single server setup + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const extensionManagementServerService = instantiationService.get(IExtensionManagementServerService); + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localWorkspaceExtension]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled for local workspace extension if it is uninstalled locally', async () => { + // multi server setup + const extensionManagementService = instantiationService.get(IExtensionManagementService); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, extensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localWorkspaceExtension]); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + + uninstallEvent.fire(localWorkspaceExtension.identifier); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled for local workspace extension if it is installed in remote', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const remoteWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), createExtensionManagementService([remoteWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is enabled for local workspace extension if it has not gallery', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test remote install action is disabled for local workspace system extension', async () => { + // multi server setup + const localWorkspaceSystemExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`), type: ExtensionType.System }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceSystemExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceSystemExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled for local ui extension if it is not installed in remote', async () => { + // multi server setup + const localUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is disabled for local ui extension if it is also installed in remote', async () => { + // multi server setup + const localUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localUIExtension]), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test remote install action is enabled for locally installed language pack extension', async () => { + // multi server setup + const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([languagePackExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + }); + + test('Test remote install action is disabled if local language pack extension is uninstalled', async () => { + // multi server setup + const extensionManagementService = instantiationService.get(IExtensionManagementService); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, extensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`) }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [languagePackExtension]); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install on remote', testObject.label); + + uninstallEvent.fire(languagePackExtension.identifier); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is enabled for remote ui extension', async () => { + // multi server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + }); + + test('Test local install action when installing remote ui extension', async () => { + // multi server setup + const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + localExtensionManagementService.onInstallExtension = onInstallExtension.event; + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const gallery = aGalleryExtension('a', { identifier: remoteUIExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + + onInstallExtension.fire({ identifier: remoteUIExtension.identifier, gallery }); + assert.ok(testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); + }); + + test('Test local install action when installing remote ui extension is finished', async () => { + // multi server setup + const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + localExtensionManagementService.onInstallExtension = onInstallExtension.event; + const onDidInstallEvent = new Emitter(); + localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const gallery = aGalleryExtension('a', { identifier: remoteUIExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + + onInstallExtension.fire({ identifier: remoteUIExtension.identifier, gallery }); + assert.ok(testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); + + const installedExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + onDidInstallEvent.fire({ identifier: installedExtension.identifier, local: installedExtension, operation: InstallOperation.Install }); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is enabled for disabled remote ui extension', async () => { + // multi server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + await instantiationService.get(IExtensionEnablementService).setEnablement([remoteUIExtension], EnablementState.DisabledGlobally); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + }); + + test('Test local install action is disabled when extension is not set', async () => { + // multi server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled for extension which is not installed', async () => { + // multi server setup + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const pager = await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = pager.firstPage[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled for remote ui extension which is disabled in env', async () => { + // multi server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + instantiationService.stub(IWorkbenchEnvironmentService, { disableExtensions: true } as IWorkbenchEnvironmentService); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled when local server is not available', async () => { + // single server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aSingleRemoteExtensionManagementServerService(instantiationService, createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled for remote ui extension if it is installed in local', async () => { + // multi server setup + const localUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localUIExtension]), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled for remoteUI extension if it is uninstalled locally', async () => { + // multi server setup + const extensionManagementService = instantiationService.get(IExtensionManagementService); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), extensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [remoteUIExtension]); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + + uninstallEvent.fire(remoteUIExtension.identifier); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is enabled for remote UI extension if it has gallery', async () => { + // multi server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test local install action is disabled for remote UI system extension', async () => { + // multi server setup + const remoteUISystemExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }), type: ExtensionType.System }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUISystemExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUISystemExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled for remote workspace extension if it is not installed in local', async () => { + // multi server setup + const remoteWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is disabled for remote workspace extension if it is also installed in local', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspae' }, { location: URI.file(`pub.a`) }); + const remoteWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), createExtensionManagementService([remoteWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(!testObject.enabled); + }); + + test('Test local install action is enabled for remotely installed language pack extension', async () => { + // multi server setup + const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([languagePackExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + assert.equal('extension-action prominent install', testObject.class); + }); + + test('Test local install action is disabled if remote language pack extension is uninstalled', async () => { + // multi server setup + const extensionManagementService = instantiationService.get(IExtensionManagementService); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), extensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [languagePackExtension]); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + + uninstallEvent.fire(languagePackExtension.identifier); + assert.ok(!testObject.enabled); + }); test(`RecommendToFolderAction`, () => { // TODO: Implement test @@ -1379,4 +2238,61 @@ suite('ExtensionsActions Test', () => { return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null! }; } + function aSingleRemoteExtensionManagementServerService(instantiationService: TestInstantiationService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService { + const remoteExtensionManagementServer: IExtensionManagementServer = { + authority: 'vscode-remote', + label: 'remote', + extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() + }; + return { + _serviceBrand: {}, + localExtensionManagementServer: null, + remoteExtensionManagementServer, + getExtensionManagementServer: (location: URI) => { + if (location.scheme === REMOTE_HOST_SCHEME) { + return remoteExtensionManagementServer; + } + return null; + } + }; + } + + function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IExtensionManagementService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService { + const localExtensionManagementServer: IExtensionManagementServer = { + authority: 'vscode-local', + label: 'local', + extensionManagementService: localExtensionManagementService || createExtensionManagementService() + }; + const remoteExtensionManagementServer: IExtensionManagementServer = { + authority: 'vscode-remote', + label: 'remote', + extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() + }; + 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 createExtensionManagementService(installed: ILocalExtension[] = []): IExtensionManagementService { + return { + onInstallExtension: Event.None, + onDidInstallExtension: Event.None, + onUninstallExtension: Event.None, + onDidUninstallExtension: Event.None, + getInstalled: () => Promise.resolve(installed), + installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported')) + }; + } + }); 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 a57f2f12f64..cd6d14c858d 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,10 +12,11 @@ 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/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { Emitter } from 'vs/base/common/event'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -41,15 +42,15 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { INotificationService, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; import { URLService } from 'vs/platform/url/common/urlService'; -import { IExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService'; import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { IFileService } from 'vs/platform/files/common/files'; const mockExtensionGallery: IGalleryExtension[] = [ 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 c9ad5d996c8..cf2b6c79522 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 @@ -6,19 +6,20 @@ import * as assert from 'assert'; import { assign } from 'vs/base/common/objects'; import { generateUuid } from 'vs/base/common/uuid'; -import { ExtensionsListView } from 'vs/workbench/contrib/extensions/electron-browser/extensionsViews'; +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'; import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IURLService } from 'vs/platform/url/common/url'; import { Emitter } from 'vs/base/common/event'; import { IPager } from 'vs/base/common/paging'; @@ -34,13 +35,17 @@ import { URLService } from 'vs/platform/url/common/urlService'; import { URI } from 'vs/base/common/uri'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { SinonStub } from 'sinon'; -import { IExperimentService, ExperimentService, ExperimentState, ExperimentActionType } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService, ExperimentState, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; 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'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; suite('ExtensionsListView Tests', () => { @@ -90,11 +95,12 @@ suite('ExtensionsListView Tests', () => { instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event); instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); instantiationService.stub(IRemoteAgentService, RemoteAgentService); + instantiationService.stub(IContextKeyService, MockContextKeyService); 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) { } @@ -142,8 +148,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 783230407cc..04ed61d0d8a 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,16 +9,17 @@ 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'; import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IURLService } from 'vs/platform/url/common/url'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { Event, Emitter } from 'vs/base/common/event'; @@ -111,7 +112,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { test('test gallery extension', async () => { const expected = aGalleryExtension('expectedName', { displayName: 'expectedDisplayName', - version: '1.5', + version: '1.5.0', publisherId: 'expectedPublisherId', publisher: 'expectedPublisher', publisherDisplayName: 'expectedPublisherDisplayName', @@ -139,14 +140,14 @@ suite('ExtensionsWorkbenchServiceTest', () => { assert.equal(1, pagedResponse.firstPage.length); const actual = pagedResponse.firstPage[0]; - assert.equal(null, actual.type); + assert.equal(ExtensionType.User, actual.type); assert.equal('expectedName', actual.name); assert.equal('expectedDisplayName', actual.displayName); assert.equal('expectedpublisher.expectedname', actual.identifier.id); assert.equal('expectedPublisher', actual.publisher); assert.equal('expectedPublisherDisplayName', actual.publisherDisplayName); - assert.equal('1.5', actual.version); - assert.equal('1.5', actual.latestVersion); + assert.equal('1.5.0', actual.version); + assert.equal('1.5.0', actual.latestVersion); assert.equal('expectedDescription', actual.description); assert.equal('uri:icon', actual.iconUrl); assert.equal('fallback:icon', actual.iconUrlFallback); @@ -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/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index c250dcea937..c3a03ba964e 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -42,16 +42,38 @@ CommandsRegistry.registerCommand({ // Always use integrated terminal when using a remote const useIntegratedTerminal = remoteAgentService.getConnection() || configurationService.getValue().terminal.explorerKind === 'integrated'; if (useIntegratedTerminal) { - distinct(targets.map(({ stat }) => stat!.isDirectory ? stat!.resource.path : paths.dirname(stat!.resource.path))).map(cwd => { + + + // TODO: Use uri for cwd in createterminal + + + const opened: { [path: string]: boolean } = {}; + targets.map(({ stat }) => { + const resource = stat!.resource; + if (stat!.isDirectory) { + return resource; + } + return URI.from({ + scheme: resource.scheme, + authority: resource.authority, + fragment: resource.fragment, + query: resource.query, + path: paths.dirname(resource.path) + }); + }).forEach(cwd => { + if (opened[cwd.path]) { + return; + } + opened[cwd.path] = true; const instance = integratedTerminalService.createTerminal({ cwd }); - if (instance && (resources.length === 1 || !resource || cwd === resource.path || cwd === paths.dirname(resource.path))) { + if (instance && (resources.length === 1 || !resource || cwd.path === resource.path || cwd.path === paths.dirname(resource.path))) { integratedTerminalService.setActiveInstance(instance); integratedTerminalService.showPanel(true); } }); } else { - distinct(targets.map(({ stat }) => stat!.isDirectory ? stat!.resource.fsPath : paths.dirname(stat!.resource.fsPath))).map(cwd => { - terminalService.openTerminal(cwd); + distinct(targets.map(({ stat }) => stat!.isDirectory ? stat!.resource.fsPath : paths.dirname(stat!.resource.fsPath))).forEach(cwd => { + terminalService!.openTerminal(cwd); }); } }); diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts index 04fa2d58140..c04d6638e87 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts @@ -16,7 +16,6 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { distinct, coalesce } from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { isLinux } from 'vs/base/common/platform'; import { ResourceMap } from 'vs/base/common/map'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -221,7 +220,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut if (oldResource.toString() === resource.toString()) { reopenFileResource = newResource; // file got moved } else { - const index = this.getIndexOfPath(resource.path, oldResource.path); + const index = this.getIndexOfPath(resource.path, oldResource.path, resources.hasToIgnoreCase(resource)); reopenFileResource = resources.joinPath(newResource, resource.path.substr(index + oldResource.path.length + 1)); // parent folder got moved } @@ -244,7 +243,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut }); } - private getIndexOfPath(path: string, candidate: string): number { + private getIndexOfPath(path: string, candidate: string, ignoreCase: boolean): number { if (candidate.length > path.length) { return -1; } @@ -253,7 +252,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut return 0; } - if (!isLinux /* ignore case */) { + if (ignoreCase) { path = path.toLowerCase(); candidate = candidate.toLowerCase(); } diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 044c0db7733..8b29304e715 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -203,7 +203,7 @@ appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, Re appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.isEqualTo(Schemas.userData))); appendEditorTitleContextMenuItem(REVEAL_IN_EXPLORER_COMMAND_ID, nls.localize('revealInSideBar', "Reveal in Side Bar"), ResourceContextKey.IsFileSystemResource); -function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr, group?: string): void { +function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void { // Menu MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index bfe380ec78b..4bde241c886 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/fileactions'; import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; -import { isWindows, isLinux } from 'vs/base/common/platform'; +import { isWindows } from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { extname, basename } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; @@ -153,7 +153,7 @@ function deleteFiles(textFileService: ITextFileService, dialogService: IDialogSe // Handle dirty let confirmDirtyPromise: Promise = Promise.resolve(true); - const dirty = textFileService.getDirty().filter(d => distinctElements.some(e => resources.isEqualOrParent(d, e.resource, !isLinux /* ignorecase */))); + const dirty = textFileService.getDirty().filter(d => distinctElements.some(e => resources.isEqualOrParent(d, e.resource))); if (dirty.length) { let message: string; if (distinctElements.length > 1) { @@ -328,11 +328,11 @@ function containsBothDirectoryAndFile(distinctElements: ExplorerItem[]): boolean } -export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean, allowOverwirte: boolean }): URI { +export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean, allowOverwrite: boolean }): URI { let name = resources.basenameOrAuthority(fileToPaste.resource); let candidate = resources.joinPath(targetFolder.resource, name); - while (true && !fileToPaste.allowOverwirte) { + while (true && !fileToPaste.allowOverwrite) { if (!targetFolder.root.find(candidate)) { break; } @@ -796,10 +796,10 @@ class ClipboardContentProvider implements ITextModelContentProvider { @IModelService private readonly modelService: IModelService ) { } - provideTextContent(resource: URI): Promise { - const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.createByFilepathOrFirstLine(resource), resource); + async provideTextContent(resource: URI): Promise { + const model = this.modelService.createModel(await this.clipboardService.readText(), this.modeService.createByFilepathOrFirstLine(resource), resource); - return Promise.resolve(model); + return model; } } @@ -1015,7 +1015,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => { // Check if target is ancestor of pasted folder const stats = await Promise.all(toPaste.map(async fileToPaste => { - if (element.resource.toString() !== fileToPaste.toString() && resources.isEqualOrParent(element.resource, fileToPaste, !isLinux /* ignorecase */)) { + if (element.resource.toString() !== fileToPaste.toString() && resources.isEqualOrParent(element.resource, fileToPaste)) { throw new Error(nls.localize('fileIsAncestor', "File to paste is an ancestor of the destination folder")); } @@ -1030,7 +1030,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => { target = element.isDirectory ? element : element.parent!; } - const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwirte: pasteShouldMove }); + const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwrite: pasteShouldMove }); // Move/Copy File if (pasteShouldMove) { diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 7155fc4dbbe..e94990d2390 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -436,13 +436,13 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -function resourcesToClipboard(resources: URI[], relative: boolean, clipboardService: IClipboardService, notificationService: INotificationService, labelService: ILabelService): void { +async function resourcesToClipboard(resources: URI[], relative: boolean, clipboardService: IClipboardService, notificationService: INotificationService, labelService: ILabelService): Promise { if (resources.length) { const lineDelimiter = isWindows ? '\r\n' : '\n'; const text = resources.map(resource => labelService.getUriLabel(resource, { relative, noPrefix: true })) .join(lineDelimiter); - clipboardService.writeText(text); + await clipboardService.writeText(text); } else { notificationService.info(nls.localize('openFileToCopy', "Open a file first to copy its path")); } @@ -456,9 +456,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_C }, id: COPY_PATH_COMMAND_ID, - handler: (accessor, resource: URI | object) => { + handler: async (accessor, resource: URI | object) => { const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService)); - resourcesToClipboard(resources, false, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService)); + await resourcesToClipboard(resources, false, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService)); } }); @@ -470,9 +470,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C) }, id: COPY_RELATIVE_PATH_COMMAND_ID, - handler: (accessor, resource: URI | object) => { + handler: async (accessor, resource: URI | object) => { const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService)); - resourcesToClipboard(resources, true, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService)); + await resourcesToClipboard(resources, true, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService)); } }); @@ -481,12 +481,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: undefined, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_P), id: 'workbench.action.files.copyPathOfActiveFile', - handler: (accessor) => { + handler: async (accessor) => { const editorService = accessor.get(IEditorService); const activeInput = editorService.activeEditor; const resource = activeInput ? activeInput.getResource() : null; const resources = resource ? [resource] : []; - resourcesToClipboard(resources, false, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService)); + await resourcesToClipboard(resources, false, accessor.get(IClipboardService), accessor.get(INotificationService), accessor.get(ILabelService)); } }); diff --git a/src/vs/workbench/contrib/files/browser/media/CollapseAll.svg b/src/vs/workbench/contrib/files/browser/media/CollapseAll.svg deleted file mode 100644 index 7d11a30f6e0..00000000000 --- a/src/vs/workbench/contrib/files/browser/media/CollapseAll.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/media/CollapseAll_inverse.svg b/src/vs/workbench/contrib/files/browser/media/CollapseAll_inverse.svg deleted file mode 100644 index 46a65fff71a..00000000000 --- a/src/vs/workbench/contrib/files/browser/media/CollapseAll_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css index 302453edb56..81b51b791f6 100644 --- a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css @@ -66,6 +66,8 @@ .explorer-viewlet .panel-header .count { min-width: fit-content; + display: flex; + align-items: center; } .explorer-viewlet .panel-header .monaco-count-badge.hidden { @@ -102,8 +104,9 @@ } .explorer-viewlet .monaco-count-badge { - padding: 1px 6px; + padding: 1px 6px 2px; margin-left: 6px; + min-height: auto; border-radius: 0; /* goes better when ellipsis shows up on narrow sidebar */ } diff --git a/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg b/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg index 09c943426e0..c109b13c3d2 100644 --- a/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg +++ b/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg @@ -1,3 +1,3 @@ - + diff --git a/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts index 66b56e6c22a..fddb247aa63 100644 --- a/src/vs/workbench/contrib/files/browser/views/emptyView.ts +++ b/src/vs/workbench/contrib/files/browser/views/emptyView.ts @@ -25,6 +25,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { ILabelService } from 'vs/platform/label/common/label'; import { Schemas } from 'vs/base/common/network'; import { isWeb } from 'vs/base/common/platform'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class EmptyView extends ViewletPanel { @@ -44,9 +45,10 @@ export class EmptyView extends ViewletPanel { @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IConfigurationService configurationService: IConfigurationService, @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, - @ILabelService private labelService: ILabelService + @ILabelService private labelService: ILabelService, + @IContextKeyService contextKeyService: IContextKeyService ) { - super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); this._register(this.contextService.onDidChangeWorkbenchState(() => this.setLabels())); this._register(this.labelService.onDidChangeFormatters(() => this.setLabels())); } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts b/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts index eec3045543e..f1708ff4d49 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts @@ -9,23 +9,23 @@ import { localize } from 'vs/nls'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { listInvalidItemForeground } from 'vs/platform/theme/common/colorRegistry'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; export class ExplorerDecorationsProvider implements IDecorationsProvider { readonly label: string = localize('label', "Explorer"); private _onDidChange = new Emitter(); - private toDispose: IDisposable[]; + private readonly toDispose = new DisposableStore(); constructor( @IExplorerService private explorerService: IExplorerService, @IWorkspaceContextService contextService: IWorkspaceContextService ) { - this.toDispose = []; - this.toDispose.push(contextService.onDidChangeWorkspaceFolders(e => { + this.toDispose.add(this._onDidChange); + this.toDispose.add(contextService.onDidChangeWorkspaceFolders(e => { this._onDidChange.fire(e.changed.concat(e.added).map(wf => wf.uri)); })); - this.toDispose.push(explorerService.onDidChangeItem(change => { + this.toDispose.add(explorerService.onDidChangeItem(change => { if (change.item) { this._onDidChange.fire([change.item.resource]); } @@ -55,7 +55,7 @@ export class ExplorerDecorationsProvider implements IDecorationsProvider { return undefined; } - dispose(): IDisposable[] { - return dispose(this.toDispose); + dispose(): void { + this.toDispose.dispose(); } } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index ed5d11edf80..9b464d453c9 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -90,7 +90,7 @@ export class ExplorerView extends ViewletPanel { @IClipboardService private clipboardService: IClipboardService, @IFileService private readonly fileService: IFileService ) { - super({ ...(options as IViewletPanelOptions), id: ExplorerView.ID, ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), id: ExplorerView.ID, ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); this.resourceContext = instantiationService.createInstance(ResourceContextKey); this._register(this.resourceContext); @@ -302,7 +302,7 @@ export class ExplorerView extends ViewletPanel { sorter: this.instantiationService.createInstance(FileSorter), dnd: this.instantiationService.createInstance(FileDragAndDrop), autoExpandSingleChildren: true - }) as WorkbenchAsyncDataTree; + }); this._register(this.tree); // Bind context keys diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 4592b3918ec..6543070e81c 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -35,7 +35,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; import { Schemas } from 'vs/base/common/network'; import { DesktopDragAndDropData, ExternalElementsDragAndDropData, ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { isMacintosh, isLinux } from 'vs/base/common/platform'; +import { isMacintosh } from 'vs/base/common/platform'; import { IDialogService, IConfirmationResult, IConfirmation, getConfirmMessage } from 'vs/platform/dialogs/common/dialogs'; import { ITextFileService, ITextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -527,7 +527,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { return true; // Can not move a file to the same parent unless we copy } - if (isEqualOrParent(target.resource, source.resource, !isLinux /* ignorecase */)) { + if (isEqualOrParent(target.resource, source.resource)) { return true; // Can not move a parent folder into one of its children } @@ -667,8 +667,9 @@ export class FileDragAndDrop implements ITreeDragAndDrop { // Check for name collisions const targetNames = new Set(); if (targetStat.children) { + const ignoreCase = hasToIgnoreCase(target.resource); targetStat.children.forEach(child => { - targetNames.add(isLinux ? child.name : child.name.toLowerCase()); + targetNames.add(ignoreCase ? child.name : child.name.toLowerCase()); }); } @@ -808,7 +809,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { // Reuse duplicate action if user copies if (isCopy) { - return this.fileService.copy(source.resource, findValidPasteFileTarget(target, { resource: source.resource, isDirectory: source.isDirectory, allowOverwirte: false })).then(stat => { + return this.fileService.copy(source.resource, findValidPasteFileTarget(target, { resource: source.resource, isDirectory: source.isDirectory, allowOverwrite: false })).then(stat => { if (!stat.isDirectory) { return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }).then(() => undefined); } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 31a5963340f..893ea55f5be 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -80,7 +80,7 @@ export class OpenEditorsView extends ViewletPanel { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize({ key: 'openEditosrSection', comment: ['Open is an adjective'] }, "Open Editors Section"), - }, keybindingService, contextMenuService, configurationService); + }, keybindingService, contextMenuService, configurationService, contextKeyService); this.structuralRefreshDelay = 0; this.listRefreshScheduler = new RunOnceScheduler(() => { @@ -219,7 +219,7 @@ export class OpenEditorsView extends ViewletPanel { ], { identityProvider: { getId: (element: OpenEditor | IEditorGroup) => element instanceof OpenEditor ? element.getId() : element.id.toString() }, dnd: new OpenEditorsDragAndDrop(this.instantiationService, this.editorGroupService) - }) as WorkbenchList; + }); this._register(this.list); this._register(this.listLabels); diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index c9d15e680c1..2d25923a2c2 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -19,6 +19,12 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; +const enum ForceOpenAs { + None, + Text, + Binary +} + /** * A file editor input is the input type for the file editor of file system resources. */ @@ -26,8 +32,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private preferredEncoding: string; private preferredMode: string; - private forceOpenAsBinary: boolean; - private forceOpenAsText: boolean; + private forceOpenAs: ForceOpenAs = ForceOpenAs.None; private textModelReference: Promise> | null; private name: string; @@ -107,7 +112,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { setPreferredEncoding(encoding: string): void { this.preferredEncoding = encoding; - this.forceOpenAsText = true; // encoding is a good hint to open the file as text + this.forceOpenAs = ForceOpenAs.Text; // encoding is a good hint to open the file as text } getPreferredMode(): string | undefined { @@ -125,17 +130,15 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { setPreferredMode(mode: string): void { this.preferredMode = mode; - this.forceOpenAsText = true; // mode is a good hint to open the file as text + this.forceOpenAs = ForceOpenAs.Text; // mode is a good hint to open the file as text } setForceOpenAsText(): void { - this.forceOpenAsText = true; - this.forceOpenAsBinary = false; + this.forceOpenAs = ForceOpenAs.Text; } setForceOpenAsBinary(): void { - this.forceOpenAsBinary = true; - this.forceOpenAsText = false; + this.forceOpenAs = ForceOpenAs.Binary; } getTypeId(): string { @@ -256,13 +259,13 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { } getPreferredEditorId(candidates: string[]): string { - return this.forceOpenAsBinary ? BINARY_FILE_EDITOR_ID : TEXT_FILE_EDITOR_ID; + return this.forceOpenAs === ForceOpenAs.Binary ? BINARY_FILE_EDITOR_ID : TEXT_FILE_EDITOR_ID; } resolve(): Promise { // Resolve as binary - if (this.forceOpenAsBinary) { + if (this.forceOpenAs === ForceOpenAs.Binary) { return this.doResolveAsBinary(); } @@ -278,7 +281,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { mode: this.preferredMode, encoding: this.preferredEncoding, reload: { async: true }, // trigger a reload of the model if it exists already but do not wait to show the model - allowBinary: this.forceOpenAsText, + allowBinary: this.forceOpenAs === ForceOpenAs.Text, reason: LoadReason.EDITOR }); diff --git a/src/vs/workbench/contrib/files/common/explorerModel.ts b/src/vs/workbench/contrib/files/common/explorerModel.ts index 1161e7e0f57..85c08590a5d 100644 --- a/src/vs/workbench/contrib/files/common/explorerModel.ts +++ b/src/vs/workbench/contrib/files/common/explorerModel.ts @@ -8,7 +8,6 @@ import { isEqual } from 'vs/base/common/extpath'; import { posix } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; import { ResourceMap } from 'vs/base/common/map'; -import { isLinux } from 'vs/base/common/platform'; import { IFileStat, IFileService } from 'vs/platform/files/common/files'; import { rtrim, startsWithIgnoreCase, startsWith, equalsIgnoreCase } from 'vs/base/common/strings'; import { coalesce } from 'vs/base/common/arrays'; @@ -275,7 +274,7 @@ export class ExplorerItem { } private getPlatformAwareName(name: string): string { - return (isLinux || !name) ? name : name.toLowerCase(); + return (!name || !resources.hasToIgnoreCase(this.resource)) ? name : name.toLowerCase(); } /** @@ -334,7 +333,7 @@ export class ExplorerItem { } private findByPath(path: string, index: number): ExplorerItem | null { - if (isEqual(rtrim(this.resource.path, posix.sep), path, !isLinux)) { + if (isEqual(rtrim(this.resource.path, posix.sep), path, resources.hasToIgnoreCase(this.resource))) { return this; } diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index cb6d96bd1ff..9d0f177a77a 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -5,7 +5,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { IExplorerService, IEditableData, IFilesConfiguration, SortOrder, SortOrderConfiguration } from 'vs/workbench/contrib/files/common/files'; import { ExplorerItem, ExplorerModel } from 'vs/workbench/contrib/files/common/explorerModel'; import { URI } from 'vs/base/common/uri'; @@ -36,7 +36,7 @@ export class ExplorerService implements IExplorerService { private _onDidChangeEditable = new Emitter(); private _onDidSelectResource = new Emitter<{ resource?: URI, reveal?: boolean }>(); private _onDidCopyItems = new Emitter<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>(); - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); private editable: { stat: ExplorerItem, data: IEditableData } | undefined; private _sortOrder: SortOrder; private cutItems: ExplorerItem[] | undefined; @@ -88,18 +88,18 @@ export class ExplorerService implements IExplorerService { (root?: URI) => getFileEventsExcludes(this.configurationService, root), (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) ); - this.disposables.push(fileEventsFilter); + this.disposables.add(fileEventsFilter); return fileEventsFilter; } @memoize get model(): ExplorerModel { const model = new ExplorerModel(this.contextService); - this.disposables.push(model); - this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e))); - this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); - this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue()))); - this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(e => { + this.disposables.add(model); + this.disposables.add(this.fileService.onAfterOperation(e => this.onFileOperation(e))); + this.disposables.add(this.fileService.onFileChanges(e => this.onFileChanges(e))); + this.disposables.add(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue()))); + this.disposables.add(this.fileService.onDidChangeFileSystemProviderRegistrations(e => { if (e.added && this.fileSystemProviderSchemes.has(e.scheme)) { // A file system provider got re-registered, we should update all file stats since they might change (got read-only) this.model.roots.forEach(r => r.forgetChildren()); @@ -108,7 +108,7 @@ export class ExplorerService implements IExplorerService { this.fileSystemProviderSchemes.add(e.scheme); } })); - this.disposables.push(model.onDidChangeRoots(() => this._onDidChangeRoots.fire())); + this.disposables.add(model.onDidChangeRoots(() => this._onDidChangeRoots.fire())); return model; } @@ -380,6 +380,6 @@ export class ExplorerService implements IExplorerService { } dispose(): void { - dispose(this.disposables); + this.disposables.dispose(); } } diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index 496534157ce..4b726da442f 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 203cacfd8e1..e93eac14556 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/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index f9c5325648a..08d95709864 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -109,8 +109,8 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowProblemsPanelActio registerAction({ id: Constants.MARKER_COPY_ACTION_ID, title: { value: localize('copyMarker', "Copy"), original: 'Copy' }, - handler(accessor) { - copyMarker(accessor.get(IPanelService), accessor.get(IClipboardService)); + async handler(accessor) { + await copyMarker(accessor.get(IPanelService), accessor.get(IClipboardService)); }, menu: { menuId: MenuId.ProblemsPanelContext, @@ -127,8 +127,8 @@ registerAction({ registerAction({ id: Constants.MARKER_COPY_MESSAGE_ACTION_ID, title: { value: localize('copyMessage', "Copy Message"), original: 'Copy Message' }, - handler(accessor) { - copyMessage(accessor.get(IPanelService), accessor.get(IClipboardService)); + async handler(accessor) { + await copyMessage(accessor.get(IPanelService), accessor.get(IClipboardService)); }, menu: { menuId: MenuId.ProblemsPanelContext, @@ -139,8 +139,8 @@ registerAction({ registerAction({ id: Constants.RELATED_INFORMATION_COPY_MESSAGE_ACTION_ID, title: { value: localize('copyMessage', "Copy Message"), original: 'Copy Message' }, - handler(accessor) { - copyRelatedInformationMessage(accessor.get(IPanelService), accessor.get(IClipboardService)); + async handler(accessor) { + await copyRelatedInformationMessage(accessor.get(IPanelService), accessor.get(IClipboardService)); }, menu: { menuId: MenuId.ProblemsPanelContext, @@ -205,32 +205,32 @@ registerAction({ } }); -function copyMarker(panelService: IPanelService, clipboardService: IClipboardService) { +async function copyMarker(panelService: IPanelService, clipboardService: IClipboardService) { const activePanel = panelService.getActivePanel(); if (activePanel instanceof MarkersPanel) { const element = (activePanel).getFocusElement(); if (element instanceof Marker) { - clipboardService.writeText(`${element}`); + await clipboardService.writeText(`${element}`); } } } -function copyMessage(panelService: IPanelService, clipboardService: IClipboardService) { +async function copyMessage(panelService: IPanelService, clipboardService: IClipboardService) { const activePanel = panelService.getActivePanel(); if (activePanel instanceof MarkersPanel) { const element = (activePanel).getFocusElement(); if (element instanceof Marker) { - clipboardService.writeText(element.marker.message); + await clipboardService.writeText(element.marker.message); } } } -function copyRelatedInformationMessage(panelService: IPanelService, clipboardService: IClipboardService) { +async function copyRelatedInformationMessage(panelService: IPanelService, clipboardService: IClipboardService) { const activePanel = panelService.getActivePanel(); if (activePanel instanceof MarkersPanel) { const element = (activePanel).getFocusElement(); if (element instanceof RelatedInformation) { - clipboardService.writeText(element.raw.message); + await clipboardService.writeText(element.raw.message); } } } diff --git a/src/vs/workbench/contrib/markers/browser/markers.ts b/src/vs/workbench/contrib/markers/browser/markers.ts index a8eeb539c22..4b27488a458 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.ts @@ -5,7 +5,7 @@ import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { MarkersModel, compareMarkersByUri } from './markersModel'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { IMarkerService, MarkerSeverity, IMarker } from 'vs/platform/markers/common/markers'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { localize } from 'vs/nls'; @@ -59,6 +59,8 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb export class ActivityUpdater extends Disposable implements IWorkbenchContribution { + private readonly activity = this._register(new MutableDisposable()); + constructor( @IActivityService private readonly activityService: IActivityService, @IMarkerService private readonly markerService: IMarkerService @@ -72,6 +74,6 @@ export class ActivityUpdater extends Disposable implements IWorkbenchContributio const { errors, warnings, infos } = this.markerService.getStatistics(); const total = errors + warnings + infos; const message = localize('totalProblems', 'Total {0} Problems', total); - this.activityService.showActivity(Constants.MARKERS_PANEL_ID, new NumberBadge(total, () => message)); + this.activity.value = this.activityService.showActivity(Constants.MARKERS_PANEL_ID, new NumberBadge(total, () => message)); } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index ad11ca74de9..71b13da1413 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -320,7 +320,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { dnd: new ResourceDragAndDrop(this.instantiationService), expandOnlyOnTwistieClick: (e: TreeElement) => e instanceof Marker && e.relatedInformation.length > 0 } - ) as any as WorkbenchObjectTree; + ); onDidChangeRenderNodeCount.input = this.tree.onDidChangeRenderNodeCount; diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index 92fd3b3c925..f2747c02b15 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -159,6 +159,7 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { toggleLayout(small: boolean) { if (this.container) { DOM.toggleClass(this.container, 'small', small); + this.adjustInputBox(); } } @@ -247,7 +248,7 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } private adjustInputBox(): void { - this.filterInputBox.inputElement.style.paddingRight = (DOM.getTotalWidth(this.controlsContainer) || 20) + 'px'; + this.filterInputBox.inputElement.style.paddingRight = DOM.hasClass(this.container, 'small') || DOM.hasClass(this.filterBadge, 'hidden') ? '25px' : '150px'; } // Action toolbar is swallowing some keys for action items which should not be for an input box diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 0facdb0c1ac..fd070d880eb 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -266,7 +266,7 @@ export class OutlinePanel extends ViewletPanel { @IContextKeyService contextKeyService: IContextKeyService, @IContextMenuService contextMenuService: IContextMenuService, ) { - super(options, keybindingService, contextMenuService, configurationService); + super(options, keybindingService, contextMenuService, configurationService, contextKeyService); this._outlineViewState.restore(this._storageService); this._contextKeyFocused = OutlineViewFocused.bindTo(contextKeyService); this._contextKeyFiltered = OutlineViewFiltered.bindTo(contextKeyService); @@ -319,6 +319,7 @@ export class OutlinePanel extends ViewletPanel { treeContainer, new OutlineVirtualDelegate(), [new OutlineGroupRenderer(), this._treeRenderer], + // https://github.com/microsoft/TypeScript/issues/32526 this._treeDataSource as IDataSource, { expandOnlyOnTwistieClick: true, @@ -328,7 +329,7 @@ export class OutlinePanel extends ViewletPanel { identityProvider: new OutlineIdentityProvider(), keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider() } - ) as WorkbenchDataTree; + ); this._disposables.push(this._tree); this._disposables.push(this._outlineViewState.onDidChange(this._onDidChangeUserState, this)); diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index 5d296f8a59a..e99147c8079 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -11,7 +11,6 @@ import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -67,11 +66,9 @@ export class ToggleOrSetOutputScrollLockAction extends Action { public static readonly ID = 'workbench.output.action.toggleOutputScrollLock'; public static readonly LABEL = nls.localize({ key: 'toggleOutputScrollLock', comment: ['Turn on / off automatic output scrolling'] }, "Toggle Output Scroll Lock"); - private toDispose: IDisposable[] = []; - constructor(id: string, label: string, @IOutputService private readonly outputService: IOutputService) { super(id, label, 'output-action output-scroll-unlock'); - this.toDispose.push(this.outputService.onActiveOutputChannel(channel => { + this._register(this.outputService.onActiveOutputChannel(channel => { const activeChannel = this.outputService.getActiveChannel(); if (activeChannel) { this.setClassAndLabel(activeChannel.scrollLock); @@ -104,11 +101,6 @@ export class ToggleOrSetOutputScrollLockAction extends Action { this.label = nls.localize('outputScrollOff', "Turn Auto Scrolling Off"); } } - - public dispose() { - super.dispose(); - this.toDispose = dispose(this.toDispose); - } } export class SwitchOutputAction extends Action { @@ -188,15 +180,13 @@ export class OpenLogOutputFile extends Action { public static readonly ID = 'workbench.output.action.openLogOutputFile'; public static readonly LABEL = nls.localize('openInLogViewer', "Open Log File"); - private disposables: IDisposable[] = []; - constructor( @IOutputService private readonly outputService: IOutputService, @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(OpenLogOutputFile.ID, OpenLogOutputFile.LABEL, 'output-action open-log-file'); - this.outputService.onActiveOutputChannel(this.update, this, this.disposables); + this._register(this.outputService.onActiveOutputChannel(this.update, this)); this.update(); } diff --git a/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts index d1c09cbce4f..052e4bd2f5c 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts @@ -49,7 +49,7 @@ export class PerfviewInput extends ResourceEditorInput { ) { super( localize('name', "Startup Performance"), - null, + undefined, PerfviewInput.Uri, undefined, textModelResolverService diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts index 3509f0f2c51..ecfdd8e2ea0 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts @@ -103,21 +103,19 @@ export class StartupProfiler implements IWorkbenchContribution { }); } - private _createPerfIssue(files: string[]): Promise { - return this._textModelResolverService.createModelReference(PerfviewInput.Uri).then(ref => { + private async _createPerfIssue(files: string[]): Promise { + const ref = await this._textModelResolverService.createModelReference(PerfviewInput.Uri); + await this._clipboardService.writeText(ref.object.textEditorModel.getValue()); + ref.dispose(); - this._clipboardService.writeText(ref.object.textEditorModel.getValue()); - ref.dispose(); - - const body = ` + const body = ` 1. :warning: We have copied additional data to your clipboard. Make sure to **paste** here. :warning: 1. :warning: Make sure to **attach** these files from your *home*-directory: :warning:\n${files.map(file => `-\`${file}\``).join('\n')} `; - const baseUrl = product.reportIssueUrl; - const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&'; + const baseUrl = product.reportIssueUrl; + const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&'; - window.open(`${baseUrl}${queryStringPrefix}body=${encodeURIComponent(body)}`); - }); + window.open(`${baseUrl}${queryStringPrefix}body=${encodeURIComponent(body)}`); } } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index d060784e1fa..d83000eaaa4 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { OS } from 'vs/base/common/platform'; -import { dispose, Disposable, toDisposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { dispose, Disposable, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; @@ -248,7 +248,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor }); } - copyKeybinding(keybinding: IKeybindingItemEntry): void { + async copyKeybinding(keybinding: IKeybindingItemEntry): Promise { this.selectEntry(keybinding); this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_COPY, keybinding.keybindingItem.command, keybinding.keybindingItem.keybinding); const userFriendlyKeybinding: IUserFriendlyKeybinding = { @@ -258,13 +258,13 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor if (keybinding.keybindingItem.when) { userFriendlyKeybinding.when = keybinding.keybindingItem.when; } - this.clipboardService.writeText(JSON.stringify(userFriendlyKeybinding, null, ' ')); + await this.clipboardService.writeText(JSON.stringify(userFriendlyKeybinding, null, ' ')); } - copyKeybindingCommand(keybinding: IKeybindingItemEntry): void { + async copyKeybindingCommand(keybinding: IKeybindingItemEntry): Promise { this.selectEntry(keybinding); this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, keybinding.keybindingItem.command, keybinding.keybindingItem.keybinding); - this.clipboardService.writeText(keybinding.keybindingItem.command); + await this.clipboardService.writeText(keybinding.keybindingItem.command); } focusSearch(): void { @@ -452,13 +452,12 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private createList(parent: HTMLElement): void { this.keybindingsListContainer = DOM.append(parent, $('.keybindings-list-container')); - this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], - { - identityProvider: { getId: (e: IListEntry) => e.id }, - ariaLabel: localize('keybindingsLabel', "Keybindings"), - setRowLineHeight: false, - horizontalScrolling: false - })) as WorkbenchList; + this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], { + identityProvider: { getId: (e: IListEntry) => e.id }, + ariaLabel: localize('keybindingsLabel', "Keybindings"), + setRowLineHeight: false, + horizontalScrolling: false + })); this._register(this.keybindingsList.onContextMenu(e => this.onContextMenu(e))); this._register(this.keybindingsList.onFocusChange(e => this.onFocusChange(e))); this._register(this.keybindingsList.onDidFocus(() => { @@ -897,6 +896,7 @@ class ActionsColumn extends Column { } dispose(): void { + super.dispose(); dispose(this.actionBar); } } @@ -1015,7 +1015,7 @@ class WhenColumn extends Column { readonly element: HTMLElement; private whenLabel: HTMLElement; private whenInput: InputBox; - private disposables: IDisposable[] = []; + private readonly renderDisposables = this._register(new DisposableStore()); private _onDidAccept: Emitter = this._register(new Emitter()); private readonly onDidAccept: Event = this._onDidAccept.event; @@ -1031,7 +1031,6 @@ class WhenColumn extends Column { ) { super(keybindingsEditor); this.element = this.create(parent); - this._register(toDisposable(() => this.disposables = dispose(this.disposables))); } private create(parent: HTMLElement): HTMLElement { @@ -1094,14 +1093,14 @@ class WhenColumn extends Column { } render(keybindingItemEntry: IKeybindingItemEntry): void { - this.disposables = dispose(this.disposables); + this.renderDisposables.clear(); DOM.clearNode(this.whenLabel); this.keybindingsEditor.onDefineWhenExpression(e => { if (keybindingItemEntry === e) { this.startEditing(); } - }, this, this.disposables); + }, this, this.renderDisposables); this.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; this.whenLabel.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry)); DOM.toggleClass(this.whenLabel, 'code', !!keybindingItemEntry.keybindingItem.when); @@ -1118,11 +1117,11 @@ class WhenColumn extends Column { this.onDidAccept(() => { this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() || '' : '', this.whenInput.value); this.keybindingsEditor.selectKeybinding(keybindingItemEntry); - }, this, this.disposables); + }, this, this.renderDisposables); this.onDidReject(() => { this.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; this.keybindingsEditor.selectKeybinding(keybindingItemEntry); - }, this, this.disposables); + }, this, this.renderDisposables); } private getAriaLabel(keybindingItemEntry: IKeybindingItemEntry): string { diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css b/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css index fddde991821..fe32e55ab66 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css @@ -3,105 +3,105 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-item-value > .setting-item-control { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-item-value > .setting-item-control { width: 100%; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-pattern { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-value { margin-right: 3px; margin-left: 2px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-pattern, -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-sibling { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-value, +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-sibling { display: inline-block; line-height: 22px; font-family: var(--monaco-monospace-font); } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-sibling { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-sibling { opacity: 0.7; margin-left: 0.5em; font-size: 0.9em; white-space: pre; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar { display: none; position: absolute; right: 0px; margin-top: 1px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row { position: relative; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:focus { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:focus { outline: none; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:hover .monaco-action-bar, -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected .monaco-action-bar { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:hover .monaco-action-bar, +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected .monaco-action-bar { display: block; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .action-label { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .action-label { width: 16px; height: 16px; padding: 2px; margin-right: 2px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-edit { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit { margin-right: 4px; } -.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-edit { +.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit { background: url("edit-light.svg") center center no-repeat; } -.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-edit { +.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit { background: url("edit-dark.svg") center center no-repeat; } -.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-remove { +.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-remove { background: url("remove-light.svg") center center no-repeat; } -.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-remove { +.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-remove { background: url("remove-dark.svg") center center no-repeat; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .monaco-text-button { width: initial; padding: 2px 14px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-item-control.setting-exclude-new-mode .setting-exclude-new-row { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-item-control.setting-list-new-mode .setting-list-new-row { display: none; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button.setting-exclude-addButton { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .monaco-text-button.setting-list-addButton { margin-right: 10px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-edit-row { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-edit-row { display: flex } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-patternInput, -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-siblingInput { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-valueInput, +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-siblingInput { height: 22px; max-width: 320px; flex: 1; margin-right: 10px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-okButton { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-okButton { margin-right: 10px; } -.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-widget { +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-widget { margin-bottom: 1px; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 89039aff9a2..0d180c8c7a1 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -13,7 +13,7 @@ import * as nls from 'vs/nls'; import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { WorkbenchStateContext, RemoteAuthorityContext, IsMacNativeContext } from 'vs/workbench/browser/contextkeys'; +import { WorkbenchStateContext, IsMacNativeContext, RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -332,10 +332,10 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ weight: KeybindingWeight.WorkbenchContrib, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS), primary: KeyMod.CtrlCmd | KeyCode.KEY_C, - handler: (accessor, args: any) => { + handler: async (accessor, args: any) => { const control = accessor.get(IEditorService).activeControl as IKeybindingsEditor; if (control) { - control.copyKeybinding(control.activeKeybindingEntry!); + await control.copyKeybinding(control.activeKeybindingEntry!); } } }); @@ -345,10 +345,10 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ weight: KeybindingWeight.WorkbenchContrib, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS), primary: 0, - handler: (accessor, args: any) => { + handler: async (accessor, args: any) => { const control = accessor.get(IEditorService).activeControl as IKeybindingsEditor; if (control) { - control.copyKeybindingCommand(control.activeKeybindingEntry!); + await control.copyKeybindingCommand(control.activeKeybindingEntry!); } } }); @@ -424,7 +424,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon title: { value: label, original: `Open Remote Settings (${hostLabel})` }, category: { value: nls.localize('preferencesCategory', "Preferences"), original: 'Preferences' } }, - when: RemoteAuthorityContext.notEqualsTo('') + when: RemoteNameContext.notEqualsTo('') }); }); } @@ -533,8 +533,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: OpenGlobalKeybindingsFileAction.ID, title: OpenGlobalKeybindingsFileAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg`)) + light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) } }, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR), @@ -817,8 +817,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, title: nls.localize('openSettingsJson', "Open Settings (JSON)"), iconLocation: { - dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-light.svg')) + dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg')), + light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg')) } }, group: 'navigation', diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 8d87975990c..cd164f0923d 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -548,8 +548,11 @@ class PreferencesRenderersController extends Disposable { const targetKey = resource.toString(); if (!this._prefsModelsForSearch.has(targetKey)) { try { - const model = this._register(await this.preferencesService.createPreferencesEditorModel(resource)); - this._prefsModelsForSearch.set(targetKey, model); + const model = await this.preferencesService.createPreferencesEditorModel(resource); + if (model) { + this._register(model); + this._prefsModelsForSearch.set(targetKey, model); + } } catch (e) { // Will throw when the settings file doesn't exist. return undefined; @@ -1116,16 +1119,19 @@ abstract class AbstractSettingsEditorContribution extends Disposable implements private _updatePreferencesRenderer(associatedPreferencesModelUri: URI): Promise | null> { return this.preferencesService.createPreferencesEditorModel(associatedPreferencesModelUri) .then(associatedPreferencesEditorModel => { - return this.preferencesRendererCreationPromise!.then(preferencesRenderer => { - if (preferencesRenderer) { - const associatedPreferencesModel = preferencesRenderer.getAssociatedPreferencesModel(); - if (associatedPreferencesModel) { - associatedPreferencesModel.dispose(); + if (associatedPreferencesEditorModel) { + return this.preferencesRendererCreationPromise!.then(preferencesRenderer => { + if (preferencesRenderer) { + const associatedPreferencesModel = preferencesRenderer.getAssociatedPreferencesModel(); + if (associatedPreferencesModel) { + associatedPreferencesModel.dispose(); + } + preferencesRenderer.setAssociatedPreferencesModel(associatedPreferencesEditorModel); } - preferencesRenderer.setAssociatedPreferencesModel(associatedPreferencesEditorModel); - } - return preferencesRenderer; - }); + return preferencesRenderer; + }); + } + return null; }); } @@ -1154,7 +1160,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable implements abstract getId(): string; } -class DefaultSettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution { +export class DefaultSettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution { static readonly ID: string = 'editor.contrib.defaultsettings'; @@ -1193,12 +1199,14 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl } protected _createPreferencesRenderer(): Promise | null> | null { - if (this.isSettingsModel()) { - return this.preferencesService.createPreferencesEditorModel(this.editor.getModel()!.uri) + const model = this.editor.getModel(); + if (model) { + return this.preferencesService.createPreferencesEditorModel(model.uri) .then(settingsModel => { if (settingsModel instanceof SettingsEditorModel && this.editor.getModel()) { switch (settingsModel.configurationTarget) { case ConfigurationTarget.USER_LOCAL: + case ConfigurationTarget.USER_REMOTE: return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel); case ConfigurationTarget.WORKSPACE: return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel); @@ -1217,31 +1225,6 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl } return null; } - - private isSettingsModel(): boolean { - const model = this.editor.getModel(); - if (!model) { - return false; - } - - if (this.preferencesService.userSettingsResource && this.preferencesService.userSettingsResource.toString() === model.uri.toString()) { - return true; - } - - if (this.preferencesService.workspaceSettingsResource && this.preferencesService.workspaceSettingsResource.toString() === model.uri.toString()) { - return true; - } - - for (const folder of this.workspaceContextService.getWorkspace().folders) { - const folderSettingsResource = this.preferencesService.getFolderSettingsResource(folder.uri); - if (folderSettingsResource && folderSettingsResource.toString() === model.uri.toString()) { - return true; - } - } - - return false; - } - } registerEditorContribution(SettingsEditorContribution); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index de35c736f91..d8abbb29809 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -9,7 +9,7 @@ import { IAction } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { Position } from 'vs/editor/common/core/position'; @@ -19,7 +19,7 @@ import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import * as nls from 'vs/nls'; import { ConfigurationTarget, IConfigurationService, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, IConfigurationNode, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -29,6 +29,8 @@ import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/ran import { DefaultSettingsHeaderWidget, EditPreferenceWidget, SettingsGroupTitleWidget, SettingsHeaderWidget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets'; import { IFilterResult, IPreferencesEditorModel, IPreferencesService, ISetting, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; +import { IMarkerService, IMarkerData, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export interface IPreferencesRenderer extends IDisposable { readonly preferencesModel: IPreferencesEditorModel; @@ -65,6 +67,8 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>()); readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event; + private unsupportedSettingsRenderer: UnsupportedSettingsRenderer; + private filterResult: IFilterResult | undefined; constructor(protected editor: ICodeEditor, readonly preferencesModel: SettingsEditorModel, @@ -78,7 +82,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter)); this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this._updatePreference(key, value, source))); this._register(this.editor.getModel()!.onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged()))); - + this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel)); } getAssociatedPreferencesModel(): IPreferencesEditorModel { @@ -102,6 +106,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend if (this.filterResult) { this.filterPreferences(this.filterResult); } + this.unsupportedSettingsRenderer.render(); } private _updatePreference(key: string, value: any, source: IIndexedSetting): void { @@ -437,12 +442,12 @@ class DefaultSettingsHeaderRenderer extends Disposable { export class SettingsGroupTitleRenderer extends Disposable implements HiddenAreasProvider { private readonly _onHiddenAreasChanged = this._register(new Emitter()); - get onHiddenAreasChanged(): Event { return this._onHiddenAreasChanged.event; } + readonly onHiddenAreasChanged: Event = this._onHiddenAreasChanged.event; private settingsGroups: ISettingsGroup[]; private hiddenGroups: ISettingsGroup[] = []; private settingsGroupTitleWidgets: SettingsGroupTitleWidget[]; - private renderDisposables: IDisposable[] = []; + private readonly renderDisposables = this._register(new DisposableStore()); constructor(private editor: ICodeEditor, @IInstantiationService private readonly instantiationService: IInstantiationService @@ -474,8 +479,8 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea const settingsGroupTitleWidget = this.instantiationService.createInstance(SettingsGroupTitleWidget, this.editor, group); settingsGroupTitleWidget.render(); this.settingsGroupTitleWidgets.push(settingsGroupTitleWidget); - this.renderDisposables.push(settingsGroupTitleWidget); - this.renderDisposables.push(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup))); + this.renderDisposables.add(settingsGroupTitleWidget); + this.renderDisposables.add(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup))); } this.settingsGroupTitleWidgets.reverse(); } @@ -515,7 +520,7 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea private disposeWidgets() { this.hiddenGroups = []; - this.renderDisposables = dispose(this.renderDisposables); + this.renderDisposables.clear(); } dispose() { @@ -946,6 +951,142 @@ class SettingHighlighter extends Disposable { } } +class UnsupportedSettingsRenderer extends Disposable { + + private renderingDelayer: Delayer = new Delayer(200); + + constructor( + private editor: ICodeEditor, + private settingsEditorModel: SettingsEditorModel, + @IMarkerService private markerService: IMarkerService, + @IWorkbenchEnvironmentService private workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IConfigurationService private configurationService: IConfigurationService, + ) { + super(); + this._register(this.editor.getModel()!.onDidChangeContent(() => this.delayedRender())); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.source === ConfigurationTarget.DEFAULT)(() => this.delayedRender())); + } + + private delayedRender(): void { + this.renderingDelayer.trigger(() => this.render()); + } + + public render(): void { + const markerData: IMarkerData[] = this.generateMarkerData(); + if (markerData.length) { + this.markerService.changeOne('preferencesEditor', this.settingsEditorModel.uri, markerData); + } else { + this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]); + } + } + + private generateMarkerData(): IMarkerData[] { + const markerData: IMarkerData[] = []; + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); + for (const settingsGroup of this.settingsEditorModel.settingsGroups) { + for (const section of settingsGroup.sections) { + for (const setting of section.settings) { + const configuration = configurationRegistry[setting.key]; + if (configuration) { + switch (this.settingsEditorModel.configurationTarget) { + case ConfigurationTarget.USER_LOCAL: + this.handleLocalUserConfiguration(setting, configuration, markerData); + break; + case ConfigurationTarget.USER_REMOTE: + this.handleRemoteUserConfiguration(setting, configuration, markerData); + break; + case ConfigurationTarget.WORKSPACE: + this.handleWorkspaceConfiguration(setting, configuration, markerData); + break; + case ConfigurationTarget.WORKSPACE_FOLDER: + this.handleWorkspaceFolderConfiguration(setting, configuration, markerData); + break; + } + } else if (!OVERRIDE_PROPERTY_PATTERN.test(setting.key)) { // Ignore override settings (language specific settings) + markerData.push({ + severity: MarkerSeverity.Hint, + tags: [MarkerTag.Unnecessary], + ...setting.range, + message: nls.localize('unknown configuration setting', "Unknown Configuration Setting") + }); + } + } + } + } + return markerData; + } + + private handleLocalUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void { + if (this.workbenchEnvironmentService.configuration.remote && configuration.scope === ConfigurationScope.MACHINE) { + markerData.push({ + severity: MarkerSeverity.Hint, + tags: [MarkerTag.Unnecessary], + ...setting.range, + message: nls.localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings") + }); + } + } + + private handleRemoteUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void { + if (configuration.scope === ConfigurationScope.APPLICATION) { + markerData.push(this.generateUnsupportedApplicationSettingMarker(setting)); + } + } + + private handleWorkspaceConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void { + if (configuration.scope === ConfigurationScope.APPLICATION) { + markerData.push(this.generateUnsupportedApplicationSettingMarker(setting)); + } + + if (configuration.scope === ConfigurationScope.MACHINE) { + markerData.push(this.generateUnsupportedMachineSettingMarker(setting)); + } + } + + private handleWorkspaceFolderConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void { + if (configuration.scope === ConfigurationScope.APPLICATION) { + markerData.push(this.generateUnsupportedApplicationSettingMarker(setting)); + } + + if (configuration.scope === ConfigurationScope.MACHINE) { + markerData.push(this.generateUnsupportedMachineSettingMarker(setting)); + } + + if (configuration.scope === ConfigurationScope.WINDOW) { + markerData.push({ + severity: MarkerSeverity.Hint, + tags: [MarkerTag.Unnecessary], + ...setting.range, + message: nls.localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.") + }); + } + } + + private generateUnsupportedApplicationSettingMarker(setting: ISetting): IMarkerData { + return { + severity: MarkerSeverity.Hint, + tags: [MarkerTag.Unnecessary], + ...setting.range, + message: nls.localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings") + }; + } + + private generateUnsupportedMachineSettingMarker(setting: ISetting): IMarkerData { + return { + severity: MarkerSeverity.Hint, + tags: [MarkerTag.Unnecessary], + ...setting.range, + message: nls.localize('unsupportedMachineSetting', "This setting can be applied only in user settings") + }; + } + + public dispose(): void { + this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]); + super.dispose(); + } + +} + class WorkspaceConfigurationRenderer extends Disposable { private decorationIds: string[] = []; diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts index 5c78ca620fa..2887abfc0f3 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ISettingsEditorModel, ISetting, ISettingsGroup, ISearchResult, IGroupFilter } from 'vs/workbench/services/preferences/common/preferences'; +import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting } from 'vs/workbench/services/preferences/common/preferences'; import { IRange } from 'vs/editor/common/core/range'; -import { distinct } from 'vs/base/common/arrays'; +import { distinct, top } from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -13,8 +13,18 @@ import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/co import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IPreferencesSearchService, ISearchProvider } from 'vs/workbench/contrib/preferences/common/preferences'; +import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfiguration } from 'vs/workbench/contrib/preferences/common/preferences'; +import { IRequestService, asJson } from 'vs/platform/request/common/request'; +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'; +import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IStringDictionary } from 'vs/base/common/collections'; +import { IProductService } from 'vs/platform/product/common/product'; export interface IEndpointDetails { urlBase?: string; @@ -24,14 +34,58 @@ export interface IEndpointDetails { export class PreferencesSearchService extends Disposable implements IPreferencesSearchService { _serviceBrand: any; + private _installedExtensions: Promise; + constructor( - @IInstantiationService protected readonly instantiationService: IInstantiationService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IProductService private readonly productService: IProductService, + @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService ) { super(); + + // This request goes to the shared process but results won't change during a window's lifetime, so cache the results. + this._installedExtensions = this.extensionManagementService.getInstalled(ExtensionType.User).then(exts => { + // Filter to enabled extensions that have settings + return exts + .filter(ext => this.extensionEnablementService.isEnabled(ext)) + .filter(ext => ext.manifest && ext.manifest.contributes && ext.manifest.contributes.configuration) + .filter(ext => !!ext.identifier.uuid); + }); + } + + private get remoteSearchAllowed(): boolean { + const workbenchSettings = this.configurationService.getValue().workbench.settings; + if (!workbenchSettings.enableNaturalLanguageSearch) { + return false; + } + + return !!this._endpoint.urlBase; + } + + private get _endpoint(): IEndpointDetails { + const workbenchSettings = this.configurationService.getValue().workbench.settings; + if (workbenchSettings.naturalLanguageSearchEndpoint) { + return { + urlBase: workbenchSettings.naturalLanguageSearchEndpoint, + key: workbenchSettings.naturalLanguageSearchKey + }; + } else { + return { + urlBase: this.productService.settingsSearchUrl + }; + } } getRemoteSearchProvider(filter: string, newExtensionsOnly = false): ISearchProvider | undefined { - return undefined; + const opts: IRemoteSearchProviderOptions = { + filter, + newExtensionsOnly, + endpoint: this._endpoint + }; + + return this.remoteSearchAllowed ? this.instantiationService.createInstance(RemoteSearchProvider, opts, this._installedExtensions) : undefined; } getLocalSearchProvider(filter: string): LocalSearchProvider { @@ -93,6 +147,299 @@ export class LocalSearchProvider implements ISearchProvider { } } +interface IRemoteSearchProviderOptions { + filter: string; + endpoint: IEndpointDetails; + newExtensionsOnly: boolean; +} + +interface IBingRequestDetails { + url: string; + body?: string; + hasMoreFilters?: boolean; + extensions?: ILocalExtension[]; +} + +class RemoteSearchProvider implements ISearchProvider { + // Must keep extension filter size under 8kb. 42 filters puts us there. + private static readonly MAX_REQUEST_FILTERS = 42; + private static readonly MAX_REQUESTS = 10; + private static readonly NEW_EXTENSIONS_MIN_SCORE = 1; + + private _remoteSearchP: Promise; + + constructor(private options: IRemoteSearchProviderOptions, private installedExtensions: Promise, + @IProductService private readonly productService: IProductService, + @IRequestService private readonly requestService: IRequestService, + @ILogService private readonly logService: ILogService + ) { + this._remoteSearchP = this.options.filter ? + Promise.resolve(this.getSettingsForFilter(this.options.filter)) : + Promise.resolve(null); + } + + searchModel(preferencesModel: ISettingsEditorModel, token?: CancellationToken): Promise { + return this._remoteSearchP.then((remoteResult) => { + if (!remoteResult) { + return null; + } + + if (token && token.isCancellationRequested) { + throw canceled(); + } + + const resultKeys = Object.keys(remoteResult.scoredResults); + const highScoreKey = top(resultKeys, (a, b) => remoteResult.scoredResults[b].score - remoteResult.scoredResults[a].score, 1)[0]; + const highScore = highScoreKey ? remoteResult.scoredResults[highScoreKey].score : 0; + const minScore = highScore / 5; + if (this.options.newExtensionsOnly) { + return this.installedExtensions.then(installedExtensions => { + const newExtsMinScore = Math.max(RemoteSearchProvider.NEW_EXTENSIONS_MIN_SCORE, minScore); + const passingScoreKeys = resultKeys + .filter(k => { + const result = remoteResult.scoredResults[k]; + const resultExtId = (result.extensionPublisher + '.' + result.extensionName).toLowerCase(); + return !installedExtensions.some(ext => ext.identifier.id.toLowerCase() === resultExtId); + }) + .filter(k => remoteResult.scoredResults[k].score >= newExtsMinScore); + + const filterMatches: ISettingMatch[] = passingScoreKeys.map(k => { + const remoteSetting = remoteResult.scoredResults[k]; + const setting = remoteSettingToISetting(remoteSetting); + return { + setting, + score: remoteSetting.score, + matches: [] // TODO + }; + }); + + return { + filterMatches, + metadata: remoteResult + }; + }); + } else { + const settingMatcher = this.getRemoteSettingMatcher(remoteResult.scoredResults, minScore, preferencesModel); + const filterMatches = preferencesModel.filterSettings(this.options.filter, group => null, settingMatcher); + return { + filterMatches, + metadata: remoteResult + }; + } + }); + } + + private async getSettingsForFilter(filter: string): Promise { + const allRequestDetails: IBingRequestDetails[] = []; + + // Only send MAX_REQUESTS requests in total just to keep it sane + for (let i = 0; i < RemoteSearchProvider.MAX_REQUESTS; i++) { + const details = await this.prepareRequest(filter, i); + allRequestDetails.push(details); + if (!details.hasMoreFilters) { + break; + } + } + + return Promise.all(allRequestDetails.map(details => this.getSettingsFromBing(details))).then(allResponses => { + // Merge all IFilterMetadata + const metadata = allResponses[0]; + metadata.requestCount = 1; + + for (const response of allResponses.slice(1)) { + metadata.requestCount++; + metadata.scoredResults = { ...metadata.scoredResults, ...response.scoredResults }; + } + + return metadata; + }); + } + + private getSettingsFromBing(details: IBingRequestDetails): Promise { + this.logService.debug(`Searching settings via ${details.url}`); + if (details.body) { + this.logService.debug(`Body: ${details.body}`); + } + + const requestType = details.body ? 'post' : 'get'; + const headers: IStringDictionary = { + 'User-Agent': 'request', + 'Content-Type': 'application/json; charset=utf-8', + }; + + if (this.options.endpoint.key) { + headers['api-key'] = this.options.endpoint.key; + } + + const start = Date.now(); + return this.requestService.request({ + type: requestType, + url: details.url, + data: details.body, + headers, + timeout: 5000 + }, CancellationToken.None).then(context => { + if (typeof context.res.statusCode === 'number' && context.res.statusCode >= 300) { + throw new Error(`${JSON.stringify(details)} returned status code: ${context.res.statusCode}`); + } + + return asJson(context); + }).then((result: any) => { + const timestamp = Date.now(); + const duration = timestamp - start; + const remoteSettings: IRemoteSetting[] = (result.value || []) + .map((r: any) => { + const key = JSON.parse(r.setting || r.Setting); + const packageId = r['packageid']; + const id = getSettingKey(key, packageId); + + const value = r['value']; + const defaultValue = value ? JSON.parse(value) : value; + + const packageName = r['packagename']; + let extensionName: string | undefined; + let extensionPublisher: string | undefined; + if (packageName && packageName.indexOf('##') >= 0) { + [extensionPublisher, extensionName] = packageName.split('##'); + } + + return { + key, + id, + defaultValue, + score: r['@search.score'], + description: JSON.parse(r['details']), + packageId, + extensionName, + extensionPublisher + }; + }); + + const scoredResults = Object.create(null); + remoteSettings.forEach(s => { + scoredResults[s.id] = s; + }); + + return { + requestUrl: details.url, + requestBody: details.body, + duration, + timestamp, + scoredResults, + context: result['@odata.context'] + }; + }); + } + + private getRemoteSettingMatcher(scoredResults: IScoredResults, minScore: number, preferencesModel: ISettingsEditorModel): ISettingMatcher { + return (setting: ISetting, group: ISettingsGroup) => { + const remoteSetting = scoredResults[getSettingKey(setting.key, group.id)] || // extension setting + scoredResults[getSettingKey(setting.key, 'core')] || // core setting + scoredResults[getSettingKey(setting.key)]; // core setting from original prod endpoint + if (remoteSetting && remoteSetting.score >= minScore) { + const settingMatches = new SettingMatches(this.options.filter, setting, false, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + return { matches: settingMatches, score: remoteSetting.score }; + } + + return null; + }; + } + + private async prepareRequest(query: string, filterPage = 0): Promise { + const verbatimQuery = query; + query = escapeSpecialChars(query); + const boost = 10; + const boostedQuery = `(${query})^${boost}`; + + // Appending Fuzzy after each word. + query = query.replace(/\ +/g, '~ ') + '~'; + + const encodedQuery = encodeURIComponent(boostedQuery + ' || ' + query); + let url = `${this.options.endpoint.urlBase}`; + + if (this.options.endpoint.key) { + url += `${API_VERSION}&${QUERY_TYPE}`; + } + + const extensions = await this.installedExtensions; + const filters = this.options.newExtensionsOnly ? + [`diminish eq 'latest'`] : + this.getVersionFilters(extensions, this.productService.settingsSearchBuildId); + + const filterStr = filters + .slice(filterPage * RemoteSearchProvider.MAX_REQUEST_FILTERS, (filterPage + 1) * RemoteSearchProvider.MAX_REQUEST_FILTERS) + .join(' or '); + const hasMoreFilters = filters.length > (filterPage + 1) * RemoteSearchProvider.MAX_REQUEST_FILTERS; + + const body = JSON.stringify({ + query: encodedQuery, + filters: encodeURIComponent(filterStr), + rawQuery: encodeURIComponent(verbatimQuery) + }); + + return { + url, + body, + hasMoreFilters + }; + } + + private getVersionFilters(exts: ILocalExtension[], buildNumber?: number): string[] { + // Only search extensions that contribute settings + const filters = exts + .filter(ext => ext.manifest.contributes && ext.manifest.contributes.configuration) + .map(ext => this.getExtensionFilter(ext)); + + if (buildNumber) { + filters.push(`(packageid eq 'core' and startbuildno le '${buildNumber}' and endbuildno ge '${buildNumber}')`); + } + + return filters; + } + + private getExtensionFilter(ext: ILocalExtension): string { + const uuid = ext.identifier.uuid; + const versionString = ext.manifest.version + .split('.') + .map(versionPart => strings.pad(versionPart, 10)) + .join(''); + + return `(packageid eq '${uuid}' and startbuildno le '${versionString}' and endbuildno ge '${versionString}')`; + } +} + +function getSettingKey(name: string, packageId?: string): string { + return packageId ? + packageId + '##' + name : + name; +} + +const API_VERSION = 'api-version=2016-09-01-Preview'; +const QUERY_TYPE = 'querytype=full'; + +function escapeSpecialChars(query: string): string { + return query.replace(/\./g, ' ') + .replace(/[\\/+\-&|!"~*?:(){}\[\]\^]/g, '\\$&') + .replace(/ /g, ' ') // collapse spaces + .trim(); +} + +function remoteSettingToISetting(remoteSetting: IRemoteSetting): IExtensionSetting { + return { + description: remoteSetting.description.split('\n'), + descriptionIsMarkdown: false, + descriptionRanges: [], + key: remoteSetting.key, + keyRange: nullRange, + value: remoteSetting.defaultValue, + range: nullRange, + valueRange: nullRange, + overrides: [], + extensionName: remoteSetting.extensionName, + extensionPublisher: remoteSetting.extensionPublisher + }; +} + export class SettingMatches { private readonly descriptionMatchingWords: Map = new Map(); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index 49beca20e0d..7eeb9c15120 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -12,7 +12,7 @@ import { Action, IAction } from 'vs/base/common/actions'; import { Emitter, Event } from 'vs/base/common/event'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, IViewZone, MouseTargetType } from 'vs/editor/browser/editorBrowser'; @@ -302,8 +302,6 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { private detailsElement: HTMLElement; private dropDownElement: HTMLElement; - private disposables: IDisposable[] = []; - constructor( action: IAction, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -312,7 +310,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { super(null, action); const workspace = this.contextService.getWorkspace(); this._folder = workspace.folders.length === 1 ? workspace.folders[0] : null; - this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged())); + this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged())); } get folder(): IWorkspaceFolder | null { @@ -347,8 +345,8 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { 'tabindex': '0' }, this.labelElement, this.detailsElement, this.dropDownElement); this._register(DOM.addDisposableListener(this.anchorElement, DOM.EventType.MOUSE_DOWN, e => DOM.EventHelper.stop(e))); - this.disposables.push(DOM.addDisposableListener(this.anchorElement, DOM.EventType.CLICK, e => this.onClick(e))); - this.disposables.push(DOM.addDisposableListener(this.anchorElement, DOM.EventType.KEY_UP, e => this.onKeyUp(e))); + this._register(DOM.addDisposableListener(this.anchorElement, DOM.EventType.CLICK, e => this.onClick(e))); + this._register(DOM.addDisposableListener(this.anchorElement, DOM.EventType.KEY_UP, e => this.onKeyUp(e))); DOM.append(this.container, this.anchorElement); @@ -460,11 +458,6 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { return label; } - - dispose(): void { - dispose(this.disposables); - super.dispose(); - } } export type SettingsTarget = ConfigurationTarget.USER_LOCAL | ConfigurationTarget.USER_REMOTE | ConfigurationTarget.WORKSPACE | URI; @@ -752,7 +745,7 @@ export class EditPreferenceWidget extends Disposable { private _editPreferenceDecoration: string[]; private readonly _onClick = this._register(new Emitter()); - get onClick(): Event { return this._onClick.event; } + readonly onClick: Event = this._onClick.event; constructor(private editor: ICodeEditor ) { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 44acebf1ed4..0d080e7d577 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -79,6 +79,7 @@ export class SettingsEditor2 extends BaseEditor { return false; } return type === SettingValueType.Enum || + type === SettingValueType.ArrayOfString || type === SettingValueType.Complex || type === SettingValueType.Boolean || type === SettingValueType.Exclude; @@ -131,6 +132,7 @@ export class SettingsEditor2 extends BaseEditor { private tocFocusedElement: SettingsTreeGroupElement | null; private settingsTreeScrollTop = 0; + private dimension: DOM.Dimension; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -278,10 +280,11 @@ export class SettingsEditor2 extends BaseEditor { } layout(dimension: DOM.Dimension): void { + this.dimension = dimension; this.layoutTrees(dimension); - const innerWidth = dimension.width - 24 * 2; // 24px padding on left and right - const monacoWidth = (innerWidth > 1000 ? 1000 : innerWidth) - 10; + const innerWidth = Math.min(1000, dimension.width) - 24 * 2; // 24px padding on left and right; + const monacoWidth = innerWidth - 10 - this.countElement.clientWidth - 12; // minus padding inside inputbox, countElement width, extra padding before countElement this.searchWidget.layout({ height: 20, width: monacoWidth }); DOM.toggleClass(this.rootElement, 'mid-width', dimension.width < 1000 && dimension.width >= 600); @@ -968,7 +971,7 @@ export class SettingsEditor2 extends BaseEditor { if (key) { const focusedKey = focusedSetting.getAttribute(AbstractSettingRenderer.SETTING_KEY_ATTR); if (focusedKey === key && - !DOM.hasClass(focusedSetting, 'setting-item-exclude')) { // update `exclude`s live, as they have a separate "submit edit" step built in before this + !DOM.hasClass(focusedSetting, 'setting-item-list')) { // update `list`s live, as they have a separate "submit edit" step built in before this this.updateModifiedLabelForKey(key); this.scheduleRefresh(focusedSetting, key); @@ -1230,7 +1233,11 @@ export class SettingsEditor2 extends BaseEditor { : 'none'; if (!this.searchResultModel) { - this.countElement.style.display = 'none'; + if (this.countElement.style.display !== 'none') { + this.countElement.style.display = 'none'; + this.layout(this.dimension); + } + DOM.removeClass(this.rootElement, 'no-results'); return; } @@ -1243,7 +1250,10 @@ export class SettingsEditor2 extends BaseEditor { default: this.countElement.innerText = localize('moreThanOneResult', "{0} Settings Found", count); } - this.countElement.style.display = 'block'; + if (this.countElement.style.display !== 'block') { + this.countElement.style.display = 'block'; + this.layout(this.dimension); + } DOM.toggleClass(this.rootElement, 'no-results', count === 0); } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 45db75ebd3b..4c48aa744d3 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -42,14 +42,15 @@ import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attach import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ITOCEntry } from 'vs/workbench/contrib/preferences/browser/settingsLayout'; import { ISettingsEditorViewState, settingKeyToDisplayFormat, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeNewExtensionsElement, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; -import { ExcludeSettingWidget, IExcludeChangeEvent, IExcludeDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsSelectListBorder, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; +import { ListSettingWidget, IListChangeEvent, IListDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsSelectListBorder, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground, ExcludeSettingWidget } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; import { ISetting, ISettingsGroup, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { isArray } from 'vs/base/common/types'; const $ = DOM.$; -function getExcludeDisplayValue(element: SettingsTreeSettingElement): IExcludeDataItem[] { +function getExcludeDisplayValue(element: SettingsTreeSettingElement): IListDataItem[] { const data = element.isConfigured ? { ...element.defaultValue, ...element.scopeValue } : element.defaultValue; @@ -62,12 +63,24 @@ function getExcludeDisplayValue(element: SettingsTreeSettingElement): IExcludeDa return { id: key, - pattern: key, + value: key, sibling }; }); } +function getListDisplayValue(element: SettingsTreeSettingElement): IListDataItem[] { + if (!element.value || !isArray(element.value)) { + return []; + } + + return element.value.map((key: string) => { + return { + value: key + }; + }); +} + export function resolveSettingsTree(tocData: ITOCEntry, coreSettingsGroups: ISettingsGroup[]): { tree: ITOCEntry, leftoverSettings: Set } { const allSettings = getFlatSettings(coreSettingsGroups); return { @@ -211,8 +224,12 @@ interface ISettingComplexItemTemplate extends ISettingItemTemplate { button: Button; } +interface ISettingListItemTemplate extends ISettingItemTemplate { + listWidget: ListSettingWidget; +} + interface ISettingExcludeItemTemplate extends ISettingItemTemplate { - excludeWidget: ExcludeSettingWidget; + excludeWidget: ListSettingWidget; } interface ISettingNewExtensionsTemplate extends IDisposableTemplate { @@ -229,6 +246,7 @@ const SETTINGS_TEXT_TEMPLATE_ID = 'settings.text.template'; const SETTINGS_NUMBER_TEMPLATE_ID = 'settings.number.template'; const SETTINGS_ENUM_TEMPLATE_ID = 'settings.enum.template'; const SETTINGS_BOOL_TEMPLATE_ID = 'settings.bool.template'; +const SETTINGS_ARRAY_TEMPLATE_ID = 'settings.array.template'; const SETTINGS_EXCLUDE_TEMPLATE_ID = 'settings.exclude.template'; const SETTINGS_COMPLEX_TEMPLATE_ID = 'settings.complex.template'; const SETTINGS_NEW_EXTENSIONS_TEMPLATE_ID = 'settings.newExtensions.template'; @@ -656,11 +674,81 @@ export class SettingComplexRenderer extends AbstractSettingRenderer implements I } } +export class SettingArrayRenderer extends AbstractSettingRenderer implements ITreeRenderer { + templateId = SETTINGS_ARRAY_TEMPLATE_ID; + + renderTemplate(container: HTMLElement): ISettingListItemTemplate { + const common = this.renderCommonTemplate(null, container, 'list'); + + const listWidget = this._instantiationService.createInstance(ListSettingWidget, common.controlElement); + listWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS); + common.toDispose.push(listWidget); + + const template: ISettingListItemTemplate = { + ...common, + listWidget + }; + + this.addSettingElementFocusHandler(template); + + common.toDispose.push(listWidget.onDidChangeList(e => this.onDidChangeList(template, e))); + + return template; + } + + private onDidChangeList(template: ISettingListItemTemplate, e: IListChangeEvent): void { + if (template.context) { + const newValue: any[] | undefined = isArray(template.context.scopeValue) + ? [...template.context.scopeValue] + : [...template.context.value]; + + // Delete value + if (e.removeIndex) { + if (!e.value && e.originalValue && e.removeIndex > -1) { + newValue.splice(e.removeIndex, 1); + } + } + // Add value + else if (e.value && !e.originalValue) { + newValue.push(e.value); + } + // Update value + else if (e.value && e.originalValue) { + const valueIndex = newValue.indexOf(e.originalValue); + if (valueIndex > -1) { + newValue[valueIndex] = e.value; + } + // For some reason, we are updating and cannot find original value + // Just append the value in this case + else { + newValue.push(e.value); + } + } + + this._onDidChangeSetting.fire({ + key: template.context.setting.key, + value: newValue, + type: template.context.valueType + }); + } + } + + renderElement(element: ITreeNode, index: number, templateData: ISettingListItemTemplate): void { + super.renderSettingElement(element, index, templateData); + } + + protected renderValue(dataElement: SettingsTreeSettingElement, template: ISettingListItemTemplate, onChange: (value: string) => void): void { + const value = getListDisplayValue(dataElement); + template.listWidget.setValue(value); + template.context = dataElement; + } +} + export class SettingExcludeRenderer extends AbstractSettingRenderer implements ITreeRenderer { templateId = SETTINGS_EXCLUDE_TEMPLATE_ID; renderTemplate(container: HTMLElement): ISettingExcludeItemTemplate { - const common = this.renderCommonTemplate(null, container, 'exclude'); + const common = this.renderCommonTemplate(null, container, 'list'); const excludeWidget = this._instantiationService.createInstance(ExcludeSettingWidget, common.controlElement); excludeWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS); @@ -673,32 +761,32 @@ export class SettingExcludeRenderer extends AbstractSettingRenderer implements I this.addSettingElementFocusHandler(template); - common.toDispose.push(excludeWidget.onDidChangeExclude(e => this.onDidChangeExclude(template, e))); + common.toDispose.push(excludeWidget.onDidChangeList(e => this.onDidChangeExclude(template, e))); return template; } - private onDidChangeExclude(template: ISettingExcludeItemTemplate, e: IExcludeChangeEvent): void { + private onDidChangeExclude(template: ISettingExcludeItemTemplate, e: IListChangeEvent): void { if (template.context) { const newValue = { ...template.context.scopeValue }; // first delete the existing entry, if present - if (e.originalPattern) { - if (e.originalPattern in template.context.defaultValue) { + if (e.originalValue) { + if (e.originalValue in template.context.defaultValue) { // delete a default by overriding it - newValue[e.originalPattern] = false; + newValue[e.originalValue] = false; } else { - delete newValue[e.originalPattern]; + delete newValue[e.originalValue]; } } // then add the new or updated entry, if present - if (e.pattern) { - if (e.pattern in template.context.defaultValue && !e.sibling) { + if (e.value) { + if (e.value in template.context.defaultValue && !e.sibling) { // add a default by deleting its override - delete newValue[e.pattern]; + delete newValue[e.value]; } else { - newValue[e.pattern] = e.sibling ? { when: e.sibling } : true; + newValue[e.value] = e.sibling ? { when: e.sibling } : true; } } @@ -1056,6 +1144,7 @@ export class SettingTreeRenderers { this._instantiationService.createInstance(SettingBoolRenderer, this.settingActions), this._instantiationService.createInstance(SettingNumberRenderer, this.settingActions), this._instantiationService.createInstance(SettingBoolRenderer, this.settingActions), + this._instantiationService.createInstance(SettingArrayRenderer, this.settingActions), this._instantiationService.createInstance(SettingComplexRenderer, this.settingActions), this._instantiationService.createInstance(SettingTextRenderer, this.settingActions), this._instantiationService.createInstance(SettingExcludeRenderer, this.settingActions), @@ -1254,23 +1343,27 @@ class SettingsTreeDelegate implements IListVirtualDelegate { + async run(context: SettingsTreeSettingElement): Promise { if (context) { - this.clipboardService.writeText(context.setting.key); + await this.clipboardService.writeText(context.setting.key); } return Promise.resolve(undefined); @@ -1434,10 +1527,10 @@ class CopySettingAsJSONAction extends Action { super(CopySettingAsJSONAction.ID, CopySettingAsJSONAction.LABEL); } - run(context: SettingsTreeSettingElement): Promise { + async run(context: SettingsTreeSettingElement): Promise { if (context) { const jsonResult = `"${context.setting.key}": ${JSON.stringify(context.value, undefined, ' ')}`; - this.clipboardService.writeText(jsonResult); + await this.clipboardService.writeText(jsonResult); } return Promise.resolve(undefined); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index 49d523d5fe2..c85026c360b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -193,6 +193,8 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { this.valueType = SettingValueType.Number; } else if (this.setting.type === 'boolean') { this.valueType = SettingValueType.Boolean; + } else if (this.setting.type === 'array' && this.setting.arrayItemType === 'string') { + this.valueType = SettingValueType.ArrayOfString; } else if (isArray(this.setting.type) && this.setting.type.indexOf(SettingValueType.Null) > -1 && this.setting.type.length === 2) { if (this.setting.type.indexOf(SettingValueType.Integer) > -1) { this.valueType = SettingValueType.NullableInteger; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index e495a488cfa..6f38e066dd4 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -12,7 +12,7 @@ import { IAction } from 'vs/base/common/actions'; import { Color, RGBA } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import 'vs/css!./media/settingsWidgets'; import { localize } from 'vs/nls'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -87,35 +87,35 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(`.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget .action-label { color: ${foregroundColor}; }`); } - // Exclude control + // List control const listHoverBackgroundColor = theme.getColor(listHoverBackground); if (listHoverBackgroundColor) { - collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:hover { background-color: ${listHoverBackgroundColor}; }`); + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:hover { background-color: ${listHoverBackgroundColor}; }`); } const listHoverForegroundColor = theme.getColor(listHoverForeground); if (listHoverForegroundColor) { - collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:hover { color: ${listHoverForegroundColor}; }`); + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:hover { color: ${listHoverForegroundColor}; }`); } const listSelectBackgroundColor = theme.getColor(listActiveSelectionBackground); if (listSelectBackgroundColor) { - collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:focus { background-color: ${listSelectBackgroundColor}; }`); + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:focus { background-color: ${listSelectBackgroundColor}; }`); } const listInactiveSelectionBackgroundColor = theme.getColor(listInactiveSelectionBackground); if (listInactiveSelectionBackgroundColor) { - collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:not(:focus) { background-color: ${listInactiveSelectionBackgroundColor}; }`); + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:not(:focus) { background-color: ${listInactiveSelectionBackgroundColor}; }`); } const listInactiveSelectionForegroundColor = theme.getColor(listInactiveSelectionForeground); if (listInactiveSelectionForegroundColor) { - collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:not(:focus) { color: ${listInactiveSelectionForegroundColor}; }`); + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:not(:focus) { color: ${listInactiveSelectionForegroundColor}; }`); } const listSelectForegroundColor = theme.getColor(listActiveSelectionForeground); if (listSelectForegroundColor) { - collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:focus { color: ${listSelectForegroundColor}; }`); + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:focus { color: ${listSelectForegroundColor}; }`); } const codeTextForegroundColor = theme.getColor(textPreformatForeground); @@ -131,15 +131,15 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -export class ExcludeSettingListModel { - private _dataItems: IExcludeDataItem[] = []; +export class ListSettingListModel { + private _dataItems: IListDataItem[] = []; private _editKey: string | null; private _selectedIdx: number | null; - get items(): IExcludeViewItem[] { + get items(): IListViewItem[] { const items = this._dataItems.map((item, i) => { - const editing = item.pattern === this._editKey; - return { + const editing = item.value === this._editKey; + return { ...item, editing, selected: i === this._selectedIdx || editing @@ -150,7 +150,7 @@ export class ExcludeSettingListModel { items.push({ editing: true, selected: true, - pattern: '', + value: '', sibling: '' }); } @@ -162,8 +162,8 @@ export class ExcludeSettingListModel { this._editKey = key; } - setValue(excludeData: IExcludeDataItem[]): void { - this._dataItems = excludeData; + setValue(listData: IListDataItem[]): void { + this._dataItems = listData; } select(idx: number): void { @@ -191,20 +191,21 @@ export class ExcludeSettingListModel { } } -export interface IExcludeChangeEvent { - originalPattern: string; - pattern?: string; +export interface IListChangeEvent { + originalValue: string; + value?: string; sibling?: string; + removeIndex?: number; } -export class ExcludeSettingWidget extends Disposable { +export class ListSettingWidget extends Disposable { private listElement: HTMLElement; - private listDisposables: IDisposable[] = []; + private readonly listDisposables = this._register(new DisposableStore()); - private model = new ExcludeSettingListModel(); + private model = new ListSettingListModel(); - private readonly _onDidChangeExclude = this._register(new Emitter()); - readonly onDidChangeExclude: Event = this._onDidChangeExclude.event; + private readonly _onDidChangeList = this._register(new Emitter()); + readonly onDidChangeList: Event = this._onDidChangeList.event; get domNode(): HTMLElement { return this.listElement; @@ -217,7 +218,7 @@ export class ExcludeSettingWidget extends Disposable { ) { super(); - this.listElement = DOM.append(container, $('.setting-exclude-widget')); + this.listElement = DOM.append(container, $('.setting-list-widget')); this.listElement.setAttribute('tabindex', '0'); DOM.append(container, this.renderAddButton()); this.renderList(); @@ -240,8 +241,26 @@ export class ExcludeSettingWidget extends Disposable { })); } - setValue(excludeData: IExcludeDataItem[]): void { - this.model.setValue(excludeData); + protected getLocalizedStrings() { + return { + deleteActionTooltip: localize('removeItem', "Remove Item"), + editActionTooltip: localize('editItem', "Edit Item"), + complexEditActionTooltip: localize('editItemInSettingsJson', "Edit Item in settings.json"), + addButtonLabel: localize('addItem', "Add Item"), + inputPlaceholder: localize('itemInputPlaceholder', "String Item..."), + siblingInputPlaceholder: localize('listSiblingInputPlaceholder', "Sibling...") + }; + } + + protected getSettingListRowLocalizedStrings(value?: string, sibling?: string) { + return { + settingListRowValueHintLabel: localize('listValueHintLabel', "List item `{0}`", value), + settingListRowSiblingHintLabel: localize('listSiblingHintLabel', "List item `{0}` with sibling `${1}`", value) + }; + } + + setValue(listData: IListDataItem[]): void { + this.model.setValue(listData); this.renderList(); } @@ -269,7 +288,7 @@ export class ExcludeSettingWidget extends Disposable { const item = this.model.items[targetIdx]; if (item) { - this.editSetting(item.pattern); + this.editSetting(item.value); e.preventDefault(); e.stopPropagation(); } @@ -286,7 +305,7 @@ export class ExcludeSettingWidget extends Disposable { return -1; } - const element = DOM.findParentWithClass((e.target), 'setting-exclude-row'); + const element = DOM.findParentWithClass((e.target), 'setting-list-row'); if (!element) { return -1; } @@ -304,10 +323,10 @@ export class ExcludeSettingWidget extends Disposable { const focused = DOM.isAncestor(document.activeElement, this.listElement); DOM.clearNode(this.listElement); - this.listDisposables = dispose(this.listDisposables); + this.listDisposables.clear(); - const newMode = this.model.items.some(item => !!(item.editing && !item.pattern)); - DOM.toggleClass(this.container, 'setting-exclude-new-mode', newMode); + const newMode = this.model.items.some(item => !!(item.editing && !item.value)); + DOM.toggleClass(this.container, 'setting-list-new-mode', newMode); this.model.items .map((item, i) => this.renderItem(item, i, focused)) @@ -317,22 +336,22 @@ export class ExcludeSettingWidget extends Disposable { this.listElement.style.height = listHeight + 'px'; } - private createDeleteAction(key: string): IAction { + private createDeleteAction(key: string, idx: number): IAction { return { - class: 'setting-excludeAction-remove', + class: 'setting-listAction-remove', enabled: true, - id: 'workbench.action.removeExcludeItem', - tooltip: localize('removeExcludeItem', "Remove Exclude Item"), - run: () => this._onDidChangeExclude.fire({ originalPattern: key, pattern: undefined }) + id: 'workbench.action.removeListItem', + tooltip: this.getLocalizedStrings().deleteActionTooltip, + run: () => this._onDidChangeList.fire({ originalValue: key, value: undefined, removeIndex: idx }) }; } private createEditAction(key: string): IAction { return { - class: 'setting-excludeAction-edit', + class: 'setting-listAction-edit', enabled: true, - id: 'workbench.action.editExcludeItem', - tooltip: localize('editExcludeItem', "Edit Exclude Item"), + id: 'workbench.action.editListItem', + tooltip: this.getLocalizedStrings().editActionTooltip, run: () => { this.editSetting(key); } @@ -344,34 +363,34 @@ export class ExcludeSettingWidget extends Disposable { this.renderList(); } - private renderItem(item: IExcludeViewItem, idx: number, listFocused: boolean): HTMLElement { + private renderItem(item: IListViewItem, idx: number, listFocused: boolean): HTMLElement { return item.editing ? this.renderEditItem(item) : this.renderDataItem(item, idx, listFocused); } - private renderDataItem(item: IExcludeViewItem, idx: number, listFocused: boolean): HTMLElement { - const rowElement = $('.setting-exclude-row'); + private renderDataItem(item: IListViewItem, idx: number, listFocused: boolean): HTMLElement { + const rowElement = $('.setting-list-row'); rowElement.setAttribute('data-index', idx + ''); rowElement.setAttribute('tabindex', item.selected ? '0' : '-1'); DOM.toggleClass(rowElement, 'selected', item.selected); const actionBar = new ActionBar(rowElement); - this.listDisposables.push(actionBar); + this.listDisposables.add(actionBar); - const patternElement = DOM.append(rowElement, $('.setting-exclude-pattern')); - const siblingElement = DOM.append(rowElement, $('.setting-exclude-sibling')); - patternElement.textContent = item.pattern; + const valueElement = DOM.append(rowElement, $('.setting-list-value')); + const siblingElement = DOM.append(rowElement, $('.setting-list-sibling')); + valueElement.textContent = item.value; siblingElement.textContent = item.sibling ? ('when: ' + item.sibling) : null; actionBar.push([ - this.createEditAction(item.pattern), - this.createDeleteAction(item.pattern) + this.createEditAction(item.value), + this.createDeleteAction(item.value, idx) ], { icon: true, label: false }); - rowElement.title = item.sibling ? - localize('excludeSiblingHintLabel', "Exclude files matching `{0}`, only when a file matching `{1}` is present", item.pattern, item.sibling) : - localize('excludePatternHintLabel', "Exclude files matching `{0}`", item.pattern); + rowElement.title = item.sibling + ? this.getSettingListRowLocalizedStrings(item.value, item.sibling).settingListRowSiblingHintLabel + : this.getSettingListRowLocalizedStrings(item.value, item.sibling).settingListRowValueHintLabel; if (item.selected) { if (listFocused) { @@ -385,11 +404,11 @@ export class ExcludeSettingWidget extends Disposable { } private renderAddButton(): HTMLElement { - const rowElement = $('.setting-exclude-new-row'); + const rowElement = $('.setting-list-new-row'); const startAddButton = this._register(new Button(rowElement)); - startAddButton.label = localize('addPattern', "Add Pattern"); - startAddButton.element.classList.add('setting-exclude-addButton'); + startAddButton.label = this.getLocalizedStrings().addButtonLabel; + startAddButton.element.classList.add('setting-list-addButton'); this._register(attachButtonStyler(startAddButton, this.themeService)); this._register(startAddButton.onDidClick(() => { @@ -400,16 +419,16 @@ export class ExcludeSettingWidget extends Disposable { return rowElement; } - private renderEditItem(item: IExcludeViewItem): HTMLElement { - const rowElement = $('.setting-exclude-edit-row'); + private renderEditItem(item: IListViewItem): HTMLElement { + const rowElement = $('.setting-list-edit-row'); const onSubmit = (edited: boolean) => { this.model.setEditKey(null); - const pattern = patternInput.value.trim(); - if (edited && pattern) { - this._onDidChangeExclude.fire({ - originalPattern: item.pattern, - pattern, + const value = valueInput.value.trim(); + if (edited && value) { + this._onDidChangeList.fire({ + originalValue: item.value, + value: value, sibling: siblingInput && siblingInput.value.trim() }); } @@ -425,68 +444,84 @@ export class ExcludeSettingWidget extends Disposable { } }; - const patternInput = new InputBox(rowElement, this.contextViewService, { - placeholder: localize('excludePatternInputPlaceholder', "Exclude Pattern...") + const valueInput = new InputBox(rowElement, this.contextViewService, { + placeholder: this.getLocalizedStrings().inputPlaceholder }); - patternInput.element.classList.add('setting-exclude-patternInput'); - this.listDisposables.push(attachInputBoxStyler(patternInput, this.themeService, { + + valueInput.element.classList.add('setting-list-valueInput'); + this.listDisposables.add(attachInputBoxStyler(valueInput, this.themeService, { inputBackground: settingsTextInputBackground, inputForeground: settingsTextInputForeground, inputBorder: settingsTextInputBorder })); - this.listDisposables.push(patternInput); - patternInput.value = item.pattern; - this.listDisposables.push(DOM.addStandardDisposableListener(patternInput.inputElement, DOM.EventType.KEY_DOWN, onKeydown)); + this.listDisposables.add(valueInput); + valueInput.value = item.value; + this.listDisposables.add(DOM.addStandardDisposableListener(valueInput.inputElement, DOM.EventType.KEY_DOWN, onKeydown)); let siblingInput: InputBox; if (item.sibling) { siblingInput = new InputBox(rowElement, this.contextViewService, { - placeholder: localize('excludeSiblingInputPlaceholder', "When Pattern Is Present...") + placeholder: this.getLocalizedStrings().siblingInputPlaceholder }); - siblingInput.element.classList.add('setting-exclude-siblingInput'); - this.listDisposables.push(siblingInput); - this.listDisposables.push(attachInputBoxStyler(siblingInput, this.themeService, { + siblingInput.element.classList.add('setting-list-siblingInput'); + this.listDisposables.add(siblingInput); + this.listDisposables.add(attachInputBoxStyler(siblingInput, this.themeService, { inputBackground: settingsTextInputBackground, inputForeground: settingsTextInputForeground, inputBorder: settingsTextInputBorder })); siblingInput.value = item.sibling; - this.listDisposables.push(DOM.addStandardDisposableListener(siblingInput.inputElement, DOM.EventType.KEY_DOWN, onKeydown)); + this.listDisposables.add(DOM.addStandardDisposableListener(siblingInput.inputElement, DOM.EventType.KEY_DOWN, onKeydown)); } const okButton = this._register(new Button(rowElement)); okButton.label = localize('okButton', "OK"); - okButton.element.classList.add('setting-exclude-okButton'); - this.listDisposables.push(attachButtonStyler(okButton, this.themeService)); - this.listDisposables.push(okButton.onDidClick(() => onSubmit(true))); + okButton.element.classList.add('setting-list-okButton'); + this.listDisposables.add(attachButtonStyler(okButton, this.themeService)); + this.listDisposables.add(okButton.onDidClick(() => onSubmit(true))); const cancelButton = this._register(new Button(rowElement)); cancelButton.label = localize('cancelButton', "Cancel"); - cancelButton.element.classList.add('setting-exclude-cancelButton'); - this.listDisposables.push(attachButtonStyler(cancelButton, this.themeService)); - this.listDisposables.push(cancelButton.onDidClick(() => onSubmit(false))); + cancelButton.element.classList.add('setting-list-okButton'); + this.listDisposables.add(attachButtonStyler(cancelButton, this.themeService)); + this.listDisposables.add(cancelButton.onDidClick(() => onSubmit(false))); - this.listDisposables.push( + this.listDisposables.add( disposableTimeout(() => { - patternInput.focus(); - patternInput.select(); + valueInput.focus(); + valueInput.select(); })); return rowElement; } +} - dispose() { - super.dispose(); - this.listDisposables = dispose(this.listDisposables); +export class ExcludeSettingWidget extends ListSettingWidget { + protected getLocalizedStrings() { + return { + deleteActionTooltip: localize('removeExcludeItem', "Remove Exclude Item"), + editActionTooltip: localize('editExcludeItem', "Edit Exclude Item"), + complexEditActionTooltip: localize('editExcludeItemInSettingsJson', "Edit Exclude Item in settings.json"), + addButtonLabel: localize('addPattern', "Add Pattern"), + inputPlaceholder: localize('excludePatternInputPlaceholder', "Exclude Pattern..."), + siblingInputPlaceholder: localize('excludeSiblingInputPlaceholder', "When Pattern Is Present...") + }; + } + + protected getSettingListRowLocalizedStrings(pattern?: string, sibling?: string) { + return { + settingListRowValueHintLabel: localize('excludePatternHintLabel', "Exclude files matching `{0}`", pattern), + settingListRowSiblingHintLabel: localize('excludeSiblingHintLabel', "Exclude files matching `{0}`, only when a file matching `{1}` is present", pattern, sibling) + }; } } -export interface IExcludeDataItem { - pattern: string; +export interface IListDataItem { + value: string; sibling?: string; } -interface IExcludeViewItem extends IExcludeDataItem { +interface IListViewItem extends IListDataItem { editing?: boolean; selected?: boolean; } diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index b0b5540271f..eb8c57ee939 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -62,8 +62,8 @@ export interface IKeybindingsEditor extends IEditor { updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string | undefined): Promise; removeKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; resetKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; - copyKeybinding(keybindingEntry: IKeybindingItemEntry): void; - copyKeybindingCommand(keybindingEntry: IKeybindingItemEntry): void; + copyKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; + copyKeybindingCommand(keybindingEntry: IKeybindingItemEntry): Promise; showSimilarKeybindings(keybindingEntry: IKeybindingItemEntry): void; } diff --git a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts index 246eaf2ed11..6e7f43ffcfa 100644 --- a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { isLinux } from 'vs/base/common/platform'; import { isEqual } from 'vs/base/common/resources'; import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; @@ -79,7 +78,7 @@ export class PreferencesContribution implements IWorkbenchContribution { } // Global User Settings File - if (isEqual(resource, this.environmentService.settingsResource, !isLinux)) { + if (isEqual(resource, this.environmentService.settingsResource)) { return { override: this.preferencesService.openGlobalSettings(true, options, group) }; } diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts deleted file mode 100644 index e77c49e752c..00000000000 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts +++ /dev/null @@ -1,432 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting } from 'vs/workbench/services/preferences/common/preferences'; -import { top } from 'vs/base/common/arrays'; -import * as strings from 'vs/base/common/strings'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { asJson } from 'vs/base/node/request'; -import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfiguration } from 'vs/workbench/contrib/preferences/common/preferences'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { canceled } from 'vs/base/common/errors'; -import { ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { PreferencesSearchService as LocalPreferencesSearchService, SettingMatches } from 'vs/workbench/contrib/preferences/browser/preferencesSearch'; -import { IStringDictionary } from 'vs/base/common/collections'; - -export interface IEndpointDetails { - urlBase?: string; - key?: string; -} - -export class PreferencesSearchService extends LocalPreferencesSearchService implements IPreferencesSearchService { - _serviceBrand: any; - - private _installedExtensions: Promise; - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, - @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService - ) { - super(instantiationService); - - // This request goes to the shared process but results won't change during a window's lifetime, so cache the results. - this._installedExtensions = this.extensionManagementService.getInstalled(ExtensionType.User).then(exts => { - // Filter to enabled extensions that have settings - return exts - .filter(ext => this.extensionEnablementService.isEnabled(ext)) - .filter(ext => ext.manifest && ext.manifest.contributes && ext.manifest.contributes.configuration) - .filter(ext => !!ext.identifier.uuid); - }); - } - - private get remoteSearchAllowed(): boolean { - const workbenchSettings = this.configurationService.getValue().workbench.settings; - if (!workbenchSettings.enableNaturalLanguageSearch) { - return false; - } - - return !!this._endpoint.urlBase; - } - - private get _endpoint(): IEndpointDetails { - const workbenchSettings = this.configurationService.getValue().workbench.settings; - if (workbenchSettings.naturalLanguageSearchEndpoint) { - return { - urlBase: workbenchSettings.naturalLanguageSearchEndpoint, - key: workbenchSettings.naturalLanguageSearchKey - }; - } else { - return { - urlBase: this.environmentService.settingsSearchUrl - }; - } - } - - getRemoteSearchProvider(filter: string, newExtensionsOnly = false): ISearchProvider | undefined { - const opts: IRemoteSearchProviderOptions = { - filter, - newExtensionsOnly, - endpoint: this._endpoint - }; - - return this.remoteSearchAllowed ? this.instantiationService.createInstance(RemoteSearchProvider, opts, this._installedExtensions) : undefined; - } -} - -export class LocalSearchProvider implements ISearchProvider { - static readonly EXACT_MATCH_SCORE = 10000; - static readonly START_SCORE = 1000; - - constructor(private _filter: string) { - // Remove " and : which are likely to be copypasted as part of a setting name. - // Leave other special characters which the user might want to search for. - this._filter = this._filter - .replace(/[":]/g, ' ') - .replace(/ /g, ' ') - .trim(); - } - - searchModel(preferencesModel: ISettingsEditorModel, token?: CancellationToken): Promise { - if (!this._filter) { - return Promise.resolve(null); - } - - let orderedScore = LocalSearchProvider.START_SCORE; // Sort is not stable - const settingMatcher = (setting: ISetting) => { - const matches = new SettingMatches(this._filter, setting, true, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; - const score = this._filter === setting.key ? - LocalSearchProvider.EXACT_MATCH_SCORE : - orderedScore--; - - return matches && matches.length ? - { - matches, - score - } : - null; - }; - - const filterMatches = preferencesModel.filterSettings(this._filter, this.getGroupFilter(this._filter), settingMatcher); - if (filterMatches[0] && filterMatches[0].score === LocalSearchProvider.EXACT_MATCH_SCORE) { - return Promise.resolve({ - filterMatches: filterMatches.slice(0, 1), - exactMatch: true - }); - } else { - return Promise.resolve({ - filterMatches - }); - } - } - - private getGroupFilter(filter: string): IGroupFilter { - const regex = strings.createRegExp(filter, false, { global: true }); - return (group: ISettingsGroup) => { - return regex.test(group.title); - }; - } -} - -interface IRemoteSearchProviderOptions { - filter: string; - endpoint: IEndpointDetails; - newExtensionsOnly: boolean; -} - -interface IBingRequestDetails { - url: string; - body?: string; - hasMoreFilters?: boolean; - extensions?: ILocalExtension[]; -} - -class RemoteSearchProvider implements ISearchProvider { - // Must keep extension filter size under 8kb. 42 filters puts us there. - private static readonly MAX_REQUEST_FILTERS = 42; - private static readonly MAX_REQUESTS = 10; - private static readonly NEW_EXTENSIONS_MIN_SCORE = 1; - - private _remoteSearchP: Promise; - - constructor(private options: IRemoteSearchProviderOptions, private installedExtensions: Promise, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IRequestService private readonly requestService: IRequestService, - @ILogService private readonly logService: ILogService - ) { - this._remoteSearchP = this.options.filter ? - Promise.resolve(this.getSettingsForFilter(this.options.filter)) : - Promise.resolve(null); - } - - searchModel(preferencesModel: ISettingsEditorModel, token?: CancellationToken): Promise { - return this._remoteSearchP.then((remoteResult) => { - if (!remoteResult) { - return null; - } - - if (token && token.isCancellationRequested) { - throw canceled(); - } - - const resultKeys = Object.keys(remoteResult.scoredResults); - const highScoreKey = top(resultKeys, (a, b) => remoteResult.scoredResults[b].score - remoteResult.scoredResults[a].score, 1)[0]; - const highScore = highScoreKey ? remoteResult.scoredResults[highScoreKey].score : 0; - const minScore = highScore / 5; - if (this.options.newExtensionsOnly) { - return this.installedExtensions.then(installedExtensions => { - const newExtsMinScore = Math.max(RemoteSearchProvider.NEW_EXTENSIONS_MIN_SCORE, minScore); - const passingScoreKeys = resultKeys - .filter(k => { - const result = remoteResult.scoredResults[k]; - const resultExtId = (result.extensionPublisher + '.' + result.extensionName).toLowerCase(); - return !installedExtensions.some(ext => ext.identifier.id.toLowerCase() === resultExtId); - }) - .filter(k => remoteResult.scoredResults[k].score >= newExtsMinScore); - - const filterMatches: ISettingMatch[] = passingScoreKeys.map(k => { - const remoteSetting = remoteResult.scoredResults[k]; - const setting = remoteSettingToISetting(remoteSetting); - return { - setting, - score: remoteSetting.score, - matches: [] // TODO - }; - }); - - return { - filterMatches, - metadata: remoteResult - }; - }); - } else { - const settingMatcher = this.getRemoteSettingMatcher(remoteResult.scoredResults, minScore, preferencesModel); - const filterMatches = preferencesModel.filterSettings(this.options.filter, group => null, settingMatcher); - return { - filterMatches, - metadata: remoteResult - }; - } - }); - } - - private async getSettingsForFilter(filter: string): Promise { - const allRequestDetails: IBingRequestDetails[] = []; - - // Only send MAX_REQUESTS requests in total just to keep it sane - for (let i = 0; i < RemoteSearchProvider.MAX_REQUESTS; i++) { - const details = await this.prepareRequest(filter, i); - allRequestDetails.push(details); - if (!details.hasMoreFilters) { - break; - } - } - - return Promise.all(allRequestDetails.map(details => this.getSettingsFromBing(details))).then(allResponses => { - // Merge all IFilterMetadata - const metadata = allResponses[0]; - metadata.requestCount = 1; - - for (const response of allResponses.slice(1)) { - metadata.requestCount++; - metadata.scoredResults = { ...metadata.scoredResults, ...response.scoredResults }; - } - - return metadata; - }); - } - - private getSettingsFromBing(details: IBingRequestDetails): Promise { - this.logService.debug(`Searching settings via ${details.url}`); - if (details.body) { - this.logService.debug(`Body: ${details.body}`); - } - - const requestType = details.body ? 'post' : 'get'; - const headers: IStringDictionary = { - 'User-Agent': 'request', - 'Content-Type': 'application/json; charset=utf-8', - }; - - if (this.options.endpoint.key) { - headers['api-key'] = this.options.endpoint.key; - } - - const start = Date.now(); - return this.requestService.request({ - type: requestType, - url: details.url, - data: details.body, - headers, - timeout: 5000 - }, CancellationToken.None).then(context => { - if (typeof context.res.statusCode === 'number' && context.res.statusCode >= 300) { - throw new Error(`${JSON.stringify(details)} returned status code: ${context.res.statusCode}`); - } - - return asJson(context); - }).then((result: any) => { - const timestamp = Date.now(); - const duration = timestamp - start; - const remoteSettings: IRemoteSetting[] = (result.value || []) - .map((r: any) => { - const key = JSON.parse(r.setting || r.Setting); - const packageId = r['packageid']; - const id = getSettingKey(key, packageId); - - const value = r['value']; - const defaultValue = value ? JSON.parse(value) : value; - - const packageName = r['packagename']; - let extensionName: string | undefined; - let extensionPublisher: string | undefined; - if (packageName && packageName.indexOf('##') >= 0) { - [extensionPublisher, extensionName] = packageName.split('##'); - } - - return { - key, - id, - defaultValue, - score: r['@search.score'], - description: JSON.parse(r['details']), - packageId, - extensionName, - extensionPublisher - }; - }); - - const scoredResults = Object.create(null); - remoteSettings.forEach(s => { - scoredResults[s.id] = s; - }); - - return { - requestUrl: details.url, - requestBody: details.body, - duration, - timestamp, - scoredResults, - context: result['@odata.context'] - }; - }); - } - - private getRemoteSettingMatcher(scoredResults: IScoredResults, minScore: number, preferencesModel: ISettingsEditorModel): ISettingMatcher { - return (setting: ISetting, group: ISettingsGroup) => { - const remoteSetting = scoredResults[getSettingKey(setting.key, group.id)] || // extension setting - scoredResults[getSettingKey(setting.key, 'core')] || // core setting - scoredResults[getSettingKey(setting.key)]; // core setting from original prod endpoint - if (remoteSetting && remoteSetting.score >= minScore) { - const settingMatches = new SettingMatches(this.options.filter, setting, false, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; - return { matches: settingMatches, score: remoteSetting.score }; - } - - return null; - }; - } - - private async prepareRequest(query: string, filterPage = 0): Promise { - const verbatimQuery = query; - query = escapeSpecialChars(query); - const boost = 10; - const boostedQuery = `(${query})^${boost}`; - - // Appending Fuzzy after each word. - query = query.replace(/\ +/g, '~ ') + '~'; - - const encodedQuery = encodeURIComponent(boostedQuery + ' || ' + query); - let url = `${this.options.endpoint.urlBase}`; - - if (this.options.endpoint.key) { - url += `${API_VERSION}&${QUERY_TYPE}`; - } - - const extensions = await this.installedExtensions; - const filters = this.options.newExtensionsOnly ? - [`diminish eq 'latest'`] : - this.getVersionFilters(extensions, this.environmentService.settingsSearchBuildId); - - const filterStr = filters - .slice(filterPage * RemoteSearchProvider.MAX_REQUEST_FILTERS, (filterPage + 1) * RemoteSearchProvider.MAX_REQUEST_FILTERS) - .join(' or '); - const hasMoreFilters = filters.length > (filterPage + 1) * RemoteSearchProvider.MAX_REQUEST_FILTERS; - - const body = JSON.stringify({ - query: encodedQuery, - filters: encodeURIComponent(filterStr), - rawQuery: encodeURIComponent(verbatimQuery) - }); - - return { - url, - body, - hasMoreFilters - }; - } - - private getVersionFilters(exts: ILocalExtension[], buildNumber?: number): string[] { - // Only search extensions that contribute settings - const filters = exts - .filter(ext => ext.manifest.contributes && ext.manifest.contributes.configuration) - .map(ext => this.getExtensionFilter(ext)); - - if (buildNumber) { - filters.push(`(packageid eq 'core' and startbuildno le '${buildNumber}' and endbuildno ge '${buildNumber}')`); - } - - return filters; - } - - private getExtensionFilter(ext: ILocalExtension): string { - const uuid = ext.identifier.uuid; - const versionString = ext.manifest.version - .split('.') - .map(versionPart => strings.pad(versionPart, 10)) - .join(''); - - return `(packageid eq '${uuid}' and startbuildno le '${versionString}' and endbuildno ge '${versionString}')`; - } -} - -function getSettingKey(name: string, packageId?: string): string { - return packageId ? - packageId + '##' + name : - name; -} - -const API_VERSION = 'api-version=2016-09-01-Preview'; -const QUERY_TYPE = 'querytype=full'; - -function escapeSpecialChars(query: string): string { - return query.replace(/\./g, ' ') - .replace(/[\\/+\-&|!"~*?:(){}\[\]\^]/g, '\\$&') - .replace(/ /g, ' ') // collapse spaces - .trim(); -} - -function remoteSettingToISetting(remoteSetting: IRemoteSetting): IExtensionSetting { - return { - description: remoteSetting.description.split('\n'), - descriptionIsMarkdown: false, - descriptionRanges: [], - key: remoteSetting.key, - keyRange: nullRange, - value: remoteSetting.defaultValue, - range: nullRange, - valueRange: nullRange, - overrides: [], - extensionName: remoteSetting.extensionName, - extensionPublisher: remoteSetting.extensionPublisher - }; -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution.ts index dc4f08e446e..b53f3002e94 100644 --- a/src/vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution.ts @@ -15,7 +15,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { RunOnceScheduler } from 'vs/base/common/async'; import { URI } from 'vs/base/common/uri'; import { isEqual } from 'vs/base/common/resources'; -import { isLinux, isMacintosh } from 'vs/base/common/platform'; +import { isMacintosh } from 'vs/base/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -215,7 +215,7 @@ export class WorkspaceChangeExtHostRelauncher extends Disposable implements IWor // Restart extension host if first root folder changed (impact on deprecated workspace.rootPath API) const newFirstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : undefined; - if (!isEqual(this.firstFolderResource, newFirstFolderResource, !isLinux)) { + if (!isEqual(this.firstFolderResource, newFirstFolderResource)) { this.firstFolderResource = newFirstFolderResource; this.extensionHostRestarter.schedule(); // buffer calls to extension host restart diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 78264965a27..04975876713 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -24,20 +24,21 @@ import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/plat import { ILogService } from 'vs/platform/log/common/log'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; -import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc'; +import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc'; import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc'; import { ipcRenderer as ipc } from 'electron'; import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; -import { PersistenConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; +import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import Severity from 'vs/base/common/severity'; import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { RemoteConnectionState } from 'vs/workbench/browser/contextkeys'; +import { RemoteConnectionState, Deprecated_RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; +import { IDownloadService } from 'vs/platform/download/common/download'; const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions'; const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote'; @@ -48,7 +49,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc private windowCommandMenu: IMenu; private hasWindowActions: boolean = false; private remoteAuthority: string | undefined; - private disconnected: boolean = true; + private connectionState: 'initializing' | 'connected' | 'disconnected' | undefined = undefined; constructor( @IStatusbarService private readonly statusbarService: IStatusbarService, @@ -75,7 +76,8 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc if (this.remoteAuthority) { // Pending entry until extensions are ready this.renderWindowIndicator(nls.localize('host.open', "$(sync~spin) Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID); - RemoteConnectionState.bindTo(this.contextKeyService).set('initializing'); + this.connectionState = 'initializing'; + RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', @@ -85,6 +87,23 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc }, order: 3.5 }); + + const connection = remoteAgentService.getConnection(); + if (connection) { + this._register(connection.onDidStateChange((e) => { + switch (e.type) { + case PersistentConnectionEventType.ConnectionLost: + case PersistentConnectionEventType.ReconnectionPermanentFailure: + case PersistentConnectionEventType.ReconnectionRunning: + case PersistentConnectionEventType.ReconnectionWait: + this.setDisconnected(true); + break; + case PersistentConnectionEventType.ConnectionGain: + this.setDisconnected(false); + break; + } + })); + } } extensionService.whenInstalledExtensionsRegistered().then(_ => { @@ -95,29 +114,14 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc this._register(this.windowCommandMenu.onDidChange(e => this.updateWindowActions())); this.updateWindowIndicator(); }); - - const connection = remoteAgentService.getConnection(); - if (connection) { - this._register(connection.onDidStateChange((e) => { - switch (e.type) { - case PersistenConnectionEventType.ConnectionLost: - case PersistenConnectionEventType.ReconnectionPermanentFailure: - case PersistenConnectionEventType.ReconnectionRunning: - case PersistenConnectionEventType.ReconnectionWait: - this.setDisconnected(true); - break; - case PersistenConnectionEventType.ConnectionGain: - this.setDisconnected(false); - break; - } - })); - } } private setDisconnected(isDisconnected: boolean): void { - if (this.disconnected !== isDisconnected) { - this.disconnected = isDisconnected; - RemoteConnectionState.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected' : 'connected'); + const newState = isDisconnected ? 'disconnected' : 'connected'; + if (this.connectionState !== newState) { + this.connectionState = newState; + RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); + Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected/${this.remoteAuthority!}' : this.remoteAuthority!); this.updateWindowIndicator(); } } @@ -126,7 +130,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc const windowActionCommand = (this.remoteAuthority || this.windowCommandMenu.getActions().length) ? WINDOW_ACTIONS_COMMAND_ID : undefined; if (this.remoteAuthority) { const hostLabel = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.remoteAuthority) || this.remoteAuthority; - if (!this.disconnected) { + if (this.connectionState !== 'disconnected') { this.renderWindowIndicator(`$(remote) ${hostLabel}`, nls.localize('host.tooltip', "Editing on {0}", hostLabel), windowActionCommand); } else { this.renderWindowIndicator(`$(alert) ${nls.localize('disconnectedFrom', "Disconnected from")} ${hostLabel}`, nls.localize('host.tooltipDisconnected', "Disconnected from {0}", hostLabel), windowActionCommand); @@ -162,7 +166,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc private showIndicatorActions(menu: IMenu) { - const actions = !this.disconnected || !this.remoteAuthority ? menu.getActions() : []; + const actions = menu.getActions(); const items: (IQuickPickItem | IQuickPickSeparator)[] = []; for (let actionGroup of actions) { @@ -215,12 +219,13 @@ class RemoteChannelsContribution implements IWorkbenchContribution { constructor( @ILogService logService: ILogService, @IRemoteAgentService remoteAgentService: IRemoteAgentService, - @IDialogService dialogService: IDialogService + @IDialogService dialogService: IDialogService, + @IDownloadService downloadService: IDownloadService ) { const connection = remoteAgentService.getConnection(); if (connection) { connection.registerChannel('dialog', new DialogChannel(dialogService)); - connection.registerChannel('download', new DownloadServiceChannel()); + connection.registerChannel('download', new DownloadServiceChannel(downloadService)); connection.registerChannel('loglevel', new LogLevelSetterChannel(logService)); } } @@ -296,7 +301,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { currentTimer = null; } switch (e.type) { - case PersistenConnectionEventType.ConnectionLost: + case PersistentConnectionEventType.ConnectionLost: if (!currentProgressPromiseResolve) { let promise = new Promise((resolve) => currentProgressPromiseResolve = resolve); progressService!.withProgress( @@ -313,13 +318,13 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { progressReporter!.report(nls.localize('connectionLost', "Connection Lost")); break; - case PersistenConnectionEventType.ReconnectionWait: + case PersistentConnectionEventType.ReconnectionWait: currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds); break; - case PersistenConnectionEventType.ReconnectionRunning: + case PersistentConnectionEventType.ReconnectionRunning: progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect...")); break; - case PersistenConnectionEventType.ReconnectionPermanentFailure: + case PersistentConnectionEventType.ReconnectionPermanentFailure: currentProgressPromiseResolve!(); currentProgressPromiseResolve = null; progressReporter = null; @@ -331,7 +336,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { } }); break; - case PersistenConnectionEventType.ConnectionGain: + case PersistentConnectionEventType.ConnectionGain: currentProgressPromiseResolve!(); currentProgressPromiseResolve = null; progressReporter = null; @@ -397,12 +402,45 @@ class RemoteTelemetryEnablementUpdater extends Disposable implements IWorkbenchC } } +class RemoteEmptyWorkbenchPresentation extends Disposable implements IWorkbenchContribution { + constructor( + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @IConfigurationService configurationService: IConfigurationService, + @ICommandService commandService: ICommandService, + ) { + super(); + + function shouldShowExplorer(): boolean { + const startupEditor = configurationService.getValue('workbench.startupEditor'); + return startupEditor !== 'welcomePage' && startupEditor !== 'welcomePageInEmptyWorkbench'; + } + + function shouldShowTerminal(): boolean { + return shouldShowExplorer(); + } + + const { remoteAuthority, folderUri, workspace } = environmentService.configuration; + if (remoteAuthority && !folderUri && !workspace) { + remoteAuthorityResolverService.resolveAuthority(remoteAuthority).then(() => { + if (shouldShowExplorer()) { + commandService.executeCommand('workbench.view.explorer'); + } + if (shouldShowTerminal()) { + commandService.executeCommand('workbench.action.terminal.toggleTerminal'); + } + }); + } + } +} + const workbenchContributionsRegistry = Registry.as(WorkbenchContributionsExtensions.Workbench); workbenchContributionsRegistry.registerWorkbenchContribution(RemoteChannelsContribution, LifecyclePhase.Starting); workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentDiagnosticListener, LifecyclePhase.Eventually); workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually); workbenchContributionsRegistry.registerWorkbenchContribution(RemoteWindowActiveIndicator, LifecyclePhase.Starting); workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(RemoteEmptyWorkbenchPresentation, LifecyclePhase.Starting); Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ @@ -432,4 +470,4 @@ Registry.as(ConfigurationExtensions.Configuration) } } } - }); \ No newline at end of file + }); diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts index c3fb3ae07d3..622bb7889be 100644 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts +++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts @@ -12,20 +12,21 @@ declare var self: ServiceWorkerGlobalScope; //#region --- installing/activating -self.addEventListener('install', event => { - event.waitUntil((async () => { - await caches.delete(_cacheName); // delete caches with each new version - await self.skipWaiting(); - })); +self.addEventListener('install', _event => { + console.log('SW#install'); + self.skipWaiting(); }); self.addEventListener('activate', event => { + console.log('SW#activate'); event.waitUntil((async () => { // (1) enable navigation preloads! - // (2) become available to all pages + // (2) delete caches with each new version + // (3) become available to all pages if (self.registration.navigationPreload) { await self.registration.navigationPreload.enable(); } + await caches.delete(_cacheName); await self.clients.claim(); })()); }); @@ -60,11 +61,18 @@ self.addEventListener('fetch', async (event: FetchEvent) => { }); async function respondWithDefault(event: FetchEvent): Promise { + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + // https://bugs.chromium.org/p/chromium/issues/detail?id=823392 + // https://stackoverflow.com/questions/48463483/what-causes-a-failed-to-execute-fetch-on-serviceworkerglobalscope-only-if#49719964 + // https://developer.mozilla.org/en-US/docs/Web/API/Request/cache + return new Response(undefined, { status: 504, statusText: 'Gateway Timeout (dev tools: https://bugs.chromium.org/p/chromium/issues/detail?id=823392)' }); + } return await event.preloadResponse || await fetch(event.request); } async function respondWithResource(event: FetchEvent, uri: URI): Promise { - const cachedValue = await caches.open(_cacheName).then(cache => cache.match(event.request)); + const cacheKey = event.request.url.replace('&r=1', ''); + const cachedValue = await caches.open(_cacheName).then(cache => cache.match(cacheKey)); if (cachedValue) { return cachedValue; } @@ -72,26 +80,27 @@ async function respondWithResource(event: FetchEvent, uri: URI): Promise(resolve => { const token = generateUuid(); - const resourceUri = URI.parse(uri.query); + const [first] = uri.query.split('&'); + const components = JSON.parse(first.substr(2)); _pendingFetch.set(token, async (data: ArrayBuffer, isExtensionResource: boolean) => { const res = new Response(data, { status: 200, - headers: { 'Content-Type': getMediaMime(resourceUri.path) || 'text/plain' } + headers: { 'Content-Type': getMediaMime(components.path) || 'text/plain' } }); if (isExtensionResource) { // only cache extension resources but not other // resources, esp not workspace resources - await caches.open(_cacheName).then(cache => cache.put(event.request, res.clone())); + await caches.open(_cacheName).then(cache => cache.put(cacheKey, res.clone())); } return resolve(res); }); self.clients.get(event.clientId).then(client => { - client.postMessage({ uri: resourceUri, token }); + client.postMessage({ uri: components, token }); }); }); } diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts index 1a8fa94bb4e..dfda6a1cfbb 100644 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts +++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts @@ -4,65 +4,90 @@ *--------------------------------------------------------------------------------------------*/ import { IFileService } from 'vs/platform/files/common/files'; -import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { isEqualOrParent } from 'vs/base/common/resources'; +import { ILogService } from 'vs/platform/log/common/log'; + +// load and start service worker as soon as this file +// is being loaded and later, when services are ready, +// claim this service worker so that messages can be +// replied to +const _serviceWorker = new class ServiceWorkerStarter { + + private static _url = require.toUrl('./resourceServiceWorkerMain.js'); + + private _beforeReadyEvents: ExtendableMessageEvent[] = []; + private _messageHandler?: (event: ExtendableMessageEvent) => void; + + constructor() { + navigator.serviceWorker.register(ServiceWorkerStarter._url, { scope: '/' }).then(reg => { + // console.debug('SW#reg', reg); + return reg.update(); + // }).then(() => { + // // console.debug('SW#updated', reg); + // return navigator.serviceWorker.ready; + }).then(() => { + console.info('SW#ready'); + }).catch(err => { + console.error('SW#init', err); + }); + + const handleMessage = (event: ExtendableMessageEvent) => { + if (!this._messageHandler) { + this._beforeReadyEvents.push(event); + console.debug('SW#buffered', event.data); + } else { + this._messageHandler(event); + } + }; + + navigator.serviceWorker.addEventListener('message', e => handleMessage(e as ExtendableMessageEvent)); + } + + dispose(): void { + // when to dispose? + } + + claim(handler: (event: ExtendableMessageEvent) => void): void { + this._messageHandler = handler; + this._beforeReadyEvents.forEach(this._messageHandler); + } +}; class ResourceServiceWorker { - private readonly _disposables = new DisposableStore(); - constructor( @IFileService private readonly _fileService: IFileService, @IExtensionService private readonly _extensionService: IExtensionService, + @ILogService private readonly _logService: ILogService, ) { - this._initServiceWorker(); - this._initFetchHandler(); + this._updateEarlyResourceUris(); + _serviceWorker.claim(e => this._handleMessage(e)); } - dispose(): void { - this._disposables.dispose(); - } + private _handleMessage(event: ExtendableMessageEvent): void { + this._logService.trace('SW - fetch', event.data.uri); - private _initServiceWorker(): void { - const url = require.toUrl('./resourceServiceWorkerMain.js'); - navigator.serviceWorker.register(url, { scope: '/' }).then(reg => { - // console.log('registered', reg); - return navigator.serviceWorker.ready; - }).then(() => { - // console.log('ready'); - }).catch(err => { - console.error(err); + const uri = URI.revive(event.data.uri); + Promise.all([ + this._fileService.readFile(uri), + this._isExtensionResource(uri) + ]).then(([file, isExtensionResource]) => { + if (!event.source) { + return; + } + event.source.postMessage({ + token: event.data.token, + data: file.value.buffer.buffer, + isExtensionResource + }, [file.value.buffer.buffer]); }); } - private _initFetchHandler(): void { - - const fetchListener: (this: ServiceWorkerContainer, ev: ExtendableMessageEvent) => void = event => { - const uri = URI.revive(event.data.uri); - - Promise.all([ - this._fileService.readFile(uri), - this._isExtensionResource(uri) - ]).then(([file, isExtensionResource]) => { - if (!event.source) { - return; - } - event.source.postMessage({ - token: event.data.token, - data: file.value.buffer.buffer, - isExtensionResource - }, [file.value.buffer.buffer]); - }); - }; - navigator.serviceWorker.addEventListener('message', fetchListener); - this._disposables.add(toDisposable(() => navigator.serviceWorker.removeEventListener('message', fetchListener))); - } - private async _isExtensionResource(uri: URI): Promise { for (const ext of await this._extensionService.getExtensions()) { if (isEqualOrParent(uri, ext.extensionLocation)) { @@ -71,11 +96,58 @@ class ResourceServiceWorker { } return false; } + + private _updateEarlyResourceUris(): void { + + let updateCount = 0; + + // find style-tags + const styleElements = document.querySelectorAll('style'); + for (let i = 0; i < styleElements.length; i++) { + const el = styleElements.item(i); + if (!el.sheet) { + continue; + } + const rules = (el.sheet).rules; + for (let j = 0; j < rules.length; j++) { + const rule = rules[j]; + const newCssText = this._updateResourceUris(rule.cssText); + if (newCssText) { + (el.sheet).deleteRule(j); + (el.sheet).insertRule(newCssText, j); + updateCount += 1; + } + } + } + + // find any tag using remote uris + const htmlElements = document.querySelectorAll('[style*="/vscode-resources/fetch"]'); + for (let i = 0; i < htmlElements.length; i++) { + const el = htmlElements.item(i); + const newCssText = this._updateResourceUris(el.style.cssText); + if (newCssText) { + el.style.cssText = newCssText; + updateCount += 1; + } + } + + this._logService.trace('SW - count of changed, early dom element: ', updateCount); + } + + private _updateResourceUris(cssText: string): string | undefined { + let changed = false; + let newCssText = cssText.replace(/url\((["'])?(.+?\/vscode-resources\/fetch\?.+?)\1\)/g, (_match, g1, g2, _offset, _input) => { + changed = true; + return `url(${g1 || ''}${g2}&r=1${g1 || ''})`; + }); + + return changed ? newCssText : undefined; + } } Registry.as(Extensions.Workbench).registerWorkbenchContribution( ResourceServiceWorker, - LifecyclePhase.Starting + LifecyclePhase.Ready ); diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts index a20e16e17d6..49f317ecd55 100644 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts +++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts @@ -10,7 +10,7 @@ // statement. // trigger service worker updates -const _tag = '91e182d6-d06b-40ff-a517-32df368117f8'; +const _tag = 'a6f9835e-c10e-4299-ab39-b8e29547c20a'; // loader world const baseUrl = '../../../../../'; diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 6f90e69127a..97539eb481f 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -1158,7 +1158,7 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor private enabled = false; private models: ITextModel[] = []; private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null); - private transientDisposables: IDisposable[] = []; + private readonly transientDisposables = this._register(new DisposableStore()); private stylesheet: HTMLStyleElement; constructor( @@ -1204,7 +1204,7 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor this.disable(); } - this.transientDisposables.push(this.editorService.onDidVisibleEditorsChange(() => this.onEditorsChanged())); + this.transientDisposables.add(this.editorService.onDidVisibleEditorsChange(() => this.onEditorsChanged())); this.onEditorsChanged(); this.enabled = true; } @@ -1214,7 +1214,7 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor return; } - this.transientDisposables = dispose(this.transientDisposables); + this.transientDisposables.clear(); this.models.forEach(m => this.items[m.id].dispose()); this.models = []; this.items = Object.create(null); diff --git a/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg b/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg index 9aa985bc979..5092b857329 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg +++ b/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index db9568a6eb4..beef3cdc9fb 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -18,7 +18,7 @@ import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { ContextKeyDefinedExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -115,7 +115,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'scm.acceptInput', description: { description: localize('scm accept', "SCM: Accept Input"), args: [] }, weight: KeybindingWeight.WorkbenchContrib, - when: new ContextKeyDefinedExpr('scmRepository'), + when: ContextKeyExpr.has('scmRepository'), primary: KeyMod.CtrlCmd | KeyCode.Enter, handler: accessor => { const contextKeyService = accessor.get(IContextKeyService); @@ -134,4 +134,4 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -registerSingleton(ISCMService, SCMService); \ No newline at end of file +registerSingleton(ISCMService, SCMService); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index e56bd970377..00e6d9356ce 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -234,7 +234,7 @@ export class MainPanel extends ViewletPanel { @IMenuService private readonly menuService: IMenuService, @IConfigurationService configurationService: IConfigurationService ) { - super(options, keybindingService, contextMenuService, configurationService); + super(options, keybindingService, contextMenuService, configurationService, contextKeyService); } protected renderBody(container: HTMLElement): void { @@ -245,7 +245,7 @@ export class MainPanel extends ViewletPanel { this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [renderer], { identityProvider, horizontalScrolling: false - }) as WorkbenchList; + }); this._register(renderer.onDidRenderElement(e => this.list.updateWidth(this.viewModel.repositories.indexOf(e)), null)); this._register(this.list.onSelectionChange(this.onListSelectionChange, this)); @@ -324,7 +324,7 @@ export class MainPanel extends ViewletPanel { } private onListSelectionChange(e: IListEvent): void { - if (e.elements.length > 0 && e.browserEvent) { + if (e.elements.length > 0) { const scrollTop = this.list.scrollTop; this.viewModel.setVisibleRepositories(e.elements); this.list.scrollTop = scrollTop; @@ -495,6 +495,7 @@ class ResourceRenderer implements IListRenderer const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon, data: resource.decorations } }); + template.actionBar.clear(); template.actionBar.context = resource; const disposables = new DisposableStore(); @@ -733,7 +734,7 @@ export class RepositoryPanel extends ViewletPanel { @IContextKeyService contextKeyService: IContextKeyService, @IMenuService protected menuService: IMenuService ) { - super(options, keybindingService, contextMenuService, configurationService); + super(options, keybindingService, contextMenuService, configurationService, contextKeyService); this.menus = instantiationService.createInstance(SCMMenus, this.repository.provider); this._register(this.menus); @@ -850,7 +851,7 @@ export class RepositoryPanel extends ViewletPanel { identityProvider: scmResourceIdentityProvider, keyboardNavigationLabelProvider: scmKeyboardNavigationLabelProvider, horizontalScrolling: false - }) as WorkbenchList; + }); this._register(Event.chain(this.list.onDidOpen) .map(e => e.elements[0]) diff --git a/src/vs/workbench/contrib/scm/common/scmService.ts b/src/vs/workbench/contrib/scm/common/scmService.ts index 4b5e9e6d10b..e75d7df468e 100644 --- a/src/vs/workbench/contrib/scm/common/scmService.ts +++ b/src/vs/workbench/contrib/scm/common/scmService.ts @@ -23,7 +23,7 @@ class SCMInput implements ISCMInput { } private _onDidChange = new Emitter(); - get onDidChange(): Event { return this._onDidChange.event; } + readonly onDidChange: Event = this._onDidChange.event; private _placeholder = ''; @@ -37,7 +37,7 @@ class SCMInput implements ISCMInput { } private _onDidChangePlaceholder = new Emitter(); - get onDidChangePlaceholder(): Event { return this._onDidChangePlaceholder.event; } + readonly onDidChangePlaceholder: Event = this._onDidChangePlaceholder.event; private _visible = true; @@ -51,7 +51,7 @@ class SCMInput implements ISCMInput { } private _onDidChangeVisibility = new Emitter(); - get onDidChangeVisibility(): Event { return this._onDidChangeVisibility.event; } + readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; private _validateInput: IInputValidator = () => Promise.resolve(undefined); @@ -65,7 +65,7 @@ class SCMInput implements ISCMInput { } private _onDidChangeValidateInput = new Emitter(); - get onDidChangeValidateInput(): Event { return this._onDidChangeValidateInput.event; } + readonly onDidChangeValidateInput: Event = this._onDidChangeValidateInput.event; } class SCMRepository implements ISCMRepository { @@ -118,10 +118,10 @@ export class SCMService implements ISCMService { readonly onDidChangeSelectedRepositories: Event = this._onDidChangeSelectedRepositories.event; private _onDidAddProvider = new Emitter(); - get onDidAddRepository(): Event { return this._onDidAddProvider.event; } + readonly onDidAddRepository: Event = this._onDidAddProvider.event; private _onDidRemoveProvider = new Emitter(); - get onDidRemoveRepository(): Event { return this._onDidRemoveProvider.event; } + readonly onDidRemoveRepository: Event = this._onDidRemoveProvider.event; constructor(@ILogService private readonly logService: ILogService) { } diff --git a/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg b/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg index b40063bef31..a7ea9ab29ab 100644 --- a/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg +++ b/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg @@ -1,3 +1,3 @@ - + diff --git a/src/vs/workbench/contrib/search/browser/replaceService.ts b/src/vs/workbench/contrib/search/browser/replaceService.ts index 71d38344f4c..ff9c9bacaf1 100644 --- a/src/vs/workbench/contrib/search/browser/replaceService.ts +++ b/src/vs/workbench/contrib/search/browser/replaceService.ts @@ -67,7 +67,7 @@ class ReplacePreviewModel extends Disposable { resolve(replacePreviewUri: URI): Promise { const fileResource = toFileResource(replacePreviewUri); - const fileMatch = this.searchWorkbenchService.searchModel.searchResult.matches().filter(match => match.resource().toString() === fileResource.toString())[0]; + const fileMatch = this.searchWorkbenchService.searchModel.searchResult.matches().filter(match => match.resource.toString() === fileResource.toString())[0]; return this.textModelResolverService.createModelReference(fileResource).then(ref => { ref = this._register(ref); const sourceModel = ref.object.textEditorModel; @@ -112,8 +112,8 @@ export class ReplaceService implements IReplaceService { const fileMatch = element instanceof Match ? element.parent() : element; return this.editorService.openEditor({ - leftResource: fileMatch.resource(), - rightResource: toReplaceResource(fileMatch.resource()), + leftResource: fileMatch.resource, + rightResource: toReplaceResource(fileMatch.resource), label: nls.localize('fileReplaceChanges', "{0} ↔ {1} (Replace Preview)", fileMatch.name(), fileMatch.name()), options: { preserveFocus, @@ -139,8 +139,8 @@ export class ReplaceService implements IReplaceService { } updateReplacePreview(fileMatch: FileMatch, override: boolean = false): Promise { - const replacePreviewUri = toReplaceResource(fileMatch.resource()); - return Promise.all([this.textModelResolverService.createModelReference(fileMatch.resource()), this.textModelResolverService.createModelReference(replacePreviewUri)]) + const replacePreviewUri = toReplaceResource(fileMatch.resource); + return Promise.all([this.textModelResolverService.createModelReference(fileMatch.resource), this.textModelResolverService.createModelReference(replacePreviewUri)]) .then(([sourceModelRef, replaceModelRef]) => { const sourceModel = sourceModelRef.object.textEditorModel; const replaceModel = replaceModelRef.object.textEditorModel; @@ -200,7 +200,7 @@ export class ReplaceService implements IReplaceService { private createEdit(match: Match, text: string, resource: URI | null = null): ResourceTextEdit { const fileMatch: FileMatch = match.parent(); const resourceEdit: ResourceTextEdit = { - resource: resource !== null ? resource : fileMatch.resource(), + resource: resource !== null ? resource : fileMatch.resource, edits: [{ range: match.range(), text: text diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 8c46d8864bc..8d827d437d3 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -5,7 +5,7 @@ import { Action } from 'vs/base/common/actions'; import { distinct } from 'vs/base/common/arrays'; -import { illegalArgument } from 'vs/base/common/errors'; +import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; @@ -38,7 +38,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { Extensions as ViewExtensions, IViewsRegistry } from 'vs/workbench/common/views'; import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; -import { ExplorerFolderContext, ExplorerRootContext, FilesExplorerFocusCondition } from 'vs/workbench/contrib/files/common/files'; +import { ExplorerFolderContext, ExplorerRootContext, FilesExplorerFocusCondition, IExplorerService, VIEWLET_ID as VIEWLET_ID_FILES } from 'vs/workbench/contrib/files/common/files'; import { OpenAnythingHandler } from 'vs/workbench/contrib/search/browser/openAnythingHandler'; import { OpenSymbolHandler } from 'vs/workbench/contrib/search/browser/openSymbolHandler'; import { registerContributions as replaceContributions } from 'vs/workbench/contrib/search/browser/replaceContributions'; @@ -50,12 +50,13 @@ import { registerContributions as searchWidgetContributions } from 'vs/workbench import * as Constants from 'vs/workbench/contrib/search/common/constants'; import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search'; import { ISearchHistoryService, SearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService'; -import { FileMatchOrMatch, ISearchWorkbenchService, RenderableMatch, SearchWorkbenchService } from 'vs/workbench/contrib/search/common/searchModel'; +import { FileMatchOrMatch, ISearchWorkbenchService, RenderableMatch, SearchWorkbenchService, FileMatch } from 'vs/workbench/contrib/search/common/searchModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ISearchConfiguration, ISearchConfigurationProperties, PANEL_ID, VIEWLET_ID, VIEW_CONTAINER, VIEW_ID } from 'vs/workbench/services/search/common/search'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; - +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; registerSingleton(ISearchWorkbenchService, SearchWorkbenchService, true); registerSingleton(ISearchHistoryService, SearchHistoryService, true); @@ -212,6 +213,37 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +CommandsRegistry.registerCommand({ + id: Constants.RevealInSideBarForSearchResults, + handler: (accessor, fileMatch: FileMatch) => { + const viewletService = accessor.get(IViewletService); + const explorerService = accessor.get(IExplorerService); + const contextService = accessor.get(IWorkspaceContextService); + const uri = fileMatch.resource; + + viewletService.openViewlet(VIEWLET_ID_FILES, false).then((viewlet: ExplorerViewlet) => { + if (uri && contextService.isInsideWorkspace(uri)) { + const explorerView = viewlet.getExplorerView(); + if (explorerView) { + explorerView.setExpanded(true); + explorerService.select(uri, true).then(() => explorerView.focus(), onUnexpectedError); + } + } + }); + } +}); + +const RevealInSideBarForSearchResultsCommand: ICommandAction = { + id: Constants.RevealInSideBarForSearchResults, + title: nls.localize('revealInSideBar', "Reveal in Explorer") +}; + +MenuRegistry.appendMenuItem(MenuId.SearchContext, { + command: RevealInSideBarForSearchResultsCommand, + when: ContextKeyExpr.and(Constants.FileFocusKey, Constants.HasSearchResults), + group: '2_files', +}); + MenuRegistry.appendMenuItem(MenuId.SearchContext, { command: { id: Constants.ReplaceActionId, diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 68dc2624f5a..ca96a4cd1ee 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -654,14 +654,14 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } private hasSameParent(element: RenderableMatch): boolean { - return element && element instanceof Match && element.parent().resource() === this.element.parent().resource(); + return element && element instanceof Match && element.parent().resource === this.element.parent().resource; } private hasToOpenFile(): boolean { const activeEditor = this.editorService.activeEditor; const file = activeEditor ? activeEditor.getResource() : undefined; if (file) { - return file.toString() === this.element.parent().resource().toString(); + return file.toString() === this.element.parent().resource.toString(); } return false; } @@ -671,11 +671,11 @@ function uriToClipboardString(resource: URI): string { return resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(resource.fsPath)) : resource.toString(); } -export const copyPathCommand: ICommandHandler = (accessor, fileMatch: FileMatch | FolderMatch) => { +export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatch) => { const clipboardService = accessor.get(IClipboardService); - const text = uriToClipboardString(fileMatch.resource()); - clipboardService.writeText(text); + const text = uriToClipboardString(fileMatch.resource); + await clipboardService.writeText(text); }; function matchToString(match: Match, indent = 0): string { @@ -712,7 +712,7 @@ function fileMatchToString(fileMatch: FileMatch, maxMatches: number): { text: st .slice(0, maxMatches) .map(match => matchToString(match, 2)); return { - text: `${uriToClipboardString(fileMatch.resource())}${lineDelimiter}${matchTextRows.join(lineDelimiter)}`, + text: `${uriToClipboardString(fileMatch.resource)}${lineDelimiter}${matchTextRows.join(lineDelimiter)}`, count: matchTextRows.length }; } @@ -736,7 +736,7 @@ function folderMatchToString(folderMatch: FolderMatch | BaseFolderMatch, maxMatc } const maxClipboardMatches = 1e4; -export const copyMatchCommand: ICommandHandler = (accessor, match: RenderableMatch) => { +export const copyMatchCommand: ICommandHandler = async (accessor, match: RenderableMatch) => { const clipboardService = accessor.get(IClipboardService); let text: string | undefined; @@ -749,7 +749,7 @@ export const copyMatchCommand: ICommandHandler = (accessor, match: RenderableMat } if (text) { - clipboardService.writeText(text); + await clipboardService.writeText(text); } }; @@ -768,7 +768,7 @@ function allFolderMatchesToString(folderMatches: Array { +export const copyAllCommand: ICommandHandler = async (accessor) => { const viewletService = accessor.get(IViewletService); const panelService = accessor.get(IPanelService); const clipboardService = accessor.get(IClipboardService); @@ -778,7 +778,7 @@ export const copyAllCommand: ICommandHandler = accessor => { const root = searchView.searchResult; const text = allFolderMatchesToString(root.folderMatches(), maxClipboardMatches); - clipboardService.writeText(text); + await clipboardService.writeText(text); } }; diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index 4e79b687d46..7635f1eac29 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -115,11 +115,11 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer, index: number, templateData: IFolderMatchTemplate): void { const folderMatch = node.element; if (folderMatch.hasResource()) { - const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource()); - if (workspaceFolder && resources.isEqual(workspaceFolder.uri, folderMatch.resource())) { - templateData.label.setFile(folderMatch.resource(), { fileKind: FileKind.ROOT_FOLDER, hidePath: true }); + const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource); + if (workspaceFolder && resources.isEqual(workspaceFolder.uri, folderMatch.resource)) { + templateData.label.setFile(folderMatch.resource, { fileKind: FileKind.ROOT_FOLDER, hidePath: true }); } else { - templateData.label.setFile(folderMatch.resource(), { fileKind: FileKind.FOLDER }); + templateData.label.setFile(folderMatch.resource, { fileKind: FileKind.FOLDER }); } } else { templateData.label.setLabel(nls.localize('searchFolderMatch.other.label', "Other files")); @@ -185,8 +185,8 @@ export class FileMatchRenderer extends Disposable implements ITreeRenderer, index: number, templateData: IFileMatchTemplate): void { const fileMatch = node.element; - templateData.el.setAttribute('data-resource', fileMatch.resource().toString()); - templateData.label.setFile(fileMatch.resource(), { hideIcon: false }); + templateData.el.setAttribute('data-resource', fileMatch.resource.toString()); + templateData.label.setFile(fileMatch.resource, { hideIcon: false }); const count = fileMatch.count(); templateData.badge.setCount(count); templateData.badge.setTitleFormat(count > 1 ? nls.localize('searchMatches', "{0} matches found", count) : nls.localize('searchMatch', "{0} match found", count)); @@ -316,7 +316,7 @@ export class SearchAccessibilityProvider implements IAccessibilityProvider { const element = elements[0]; return element instanceof FileMatch ? - resources.basename(element.resource()) : + resources.basename(element.resource) : undefined; } @@ -370,7 +370,7 @@ export class SearchDND implements ITreeDragAndDrop { const elements = (data as ElementsDragAndDropData).elements; const resources: URI[] = elements .filter(e => e instanceof FileMatch) - .map((fm: FileMatch) => fm.resource()); + .map((fm: FileMatch) => fm.resource); if (resources.length) { // Apply some datatransfer types to allow for dragging the element outside of the application diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 16ebfb4ed95..2daad95ca68 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -154,7 +154,7 @@ export class SearchView extends ViewletPanel { @IKeybindingService keybindingService: IKeybindingService, @IStorageService storageService: IStorageService, ) { - super({ ...(options as IViewletPanelOptions), id: VIEW_ID, ariaHeaderLabel: nls.localize('searchView', "Search") }, keybindingService, contextMenuService, configurationService); + super({ ...(options as IViewletPanelOptions), id: VIEW_ID, ariaHeaderLabel: nls.localize('searchView', "Search") }, keybindingService, contextMenuService, configurationService, contextKeyService); this.viewletVisible = Constants.SearchViewVisibleKey.bindTo(contextKeyService); this.viewletFocused = Constants.SearchViewFocusedKey.bindTo(contextKeyService); @@ -633,7 +633,7 @@ export class SearchView extends ViewletPanel { }; this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility })); - this.tree = this._register(>this.instantiationService.createInstance(WorkbenchObjectTree, + this.tree = this._register(this.instantiationService.createInstance(WorkbenchObjectTree, this.resultsElement, delegate, [ @@ -896,13 +896,13 @@ export class SearchView extends ViewletPanel { 0 : dom.getTotalHeight(this.messagesElement); - const searchResultContainerSize = this.size.height - + const searchResultContainerHeight = this.size.height - messagesSize - dom.getTotalHeight(this.searchWidgetsContainerElement); - this.resultsElement.style.height = searchResultContainerSize + 'px'; + this.resultsElement.style.height = searchResultContainerHeight + 'px'; - this.tree.layout(searchResultContainerSize, this.size.width); + this.tree.layout(searchResultContainerHeight, this.size.width); } protected layoutBody(height: number, width: number): void { @@ -1151,6 +1151,10 @@ export class SearchView extends ViewletPanel { } onQueryChanged(preserveFocus?: boolean): void { + if (!this.searchWidget.searchInput.inputBox.isInputValid()) { + return; + } + const isRegex = this.searchWidget.searchInput.getRegex(); const isWholeWords = this.searchWidget.searchInput.getWholeWords(); const isCaseSensitive = this.searchWidget.searchInput.getCaseSensitive(); @@ -1538,7 +1542,7 @@ export class SearchView extends ViewletPanel { open(element: FileMatchOrMatch, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { const selection = this.getSelectionFrom(element); - const resource = element instanceof Match ? element.parent().resource() : (element).resource(); + const resource = element instanceof Match ? element.parent().resource : (element).resource; return this.editorService.openEditor({ resource: resource, options: { @@ -1596,7 +1600,7 @@ export class SearchView extends ViewletPanel { if (!this.untitledEditorService.isDirty(resource)) { const matches = this.viewModel.searchResult.matches(); for (let i = 0, len = matches.length; i < len; i++) { - if (resource.toString() === matches[i].resource().toString()) { + if (resource.toString() === matches[i].resource.toString()) { this.viewModel.searchResult.remove(matches[i]); } } @@ -1610,11 +1614,8 @@ export class SearchView extends ViewletPanel { const matches = this.viewModel.searchResult.matches(); - for (let i = 0, len = matches.length; i < len; i++) { - if (e.contains(matches[i].resource(), FileChangeType.DELETED)) { - this.viewModel.searchResult.remove(matches[i]); - } - } + const changedMatches = matches.filter(m => e.contains(m.resource, FileChangeType.DELETED)); + this.viewModel.searchResult.remove(changedMatches); } getActions(): IAction[] { diff --git a/src/vs/workbench/contrib/search/common/constants.ts b/src/vs/workbench/contrib/search/common/constants.ts index 59a452d404e..a13dfb10def 100644 --- a/src/vs/workbench/contrib/search/common/constants.ts +++ b/src/vs/workbench/contrib/search/common/constants.ts @@ -24,6 +24,7 @@ export const CloseReplaceWidgetActionId = 'closeReplaceInFilesWidget'; export const ToggleCaseSensitiveCommandId = 'toggleSearchCaseSensitive'; export const ToggleWholeWordCommandId = 'toggleSearchWholeWord'; export const ToggleRegexCommandId = 'toggleSearchRegex'; +export const RevealInSideBarForSearchResults = 'search.action.revealInSideBar'; export const ToggleSearchViewPositionCommandId = 'search.action.toggleSearchViewPosition'; diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 5f8ba902bd9..9c4d170c1d5 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -146,7 +146,7 @@ export class Match { } } -export class FileMatch extends Disposable { +export class FileMatch extends Disposable implements IFileMatch { private static readonly _CURRENT_FIND_MATCH = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, @@ -309,7 +309,7 @@ export class FileMatch extends Disposable { } id(): string { - return this.resource().toString(); + return this.resource.toString(); } parent(): BaseFolderMatch { @@ -357,12 +357,12 @@ export class FileMatch extends Disposable { return this.matches().length; } - resource(): URI { + get resource(): URI { return this._resource; } name(): string { - return getBaseLabel(this.resource()); + return getBaseLabel(this.resource); } add(match: Match, trigger?: boolean) { @@ -432,7 +432,7 @@ export class BaseFolderMatch extends Disposable { return this._id; } - resource(): URI | null { + get resource(): URI | null { return this._resource; } @@ -441,7 +441,7 @@ export class BaseFolderMatch extends Disposable { } name(): string { - return getBaseLabel(withNullAsUndefined(this.resource())) || ''; + return getBaseLabel(withNullAsUndefined(this.resource)) || ''; } parent(): SearchResult { @@ -494,8 +494,8 @@ export class BaseFolderMatch extends Disposable { this._onChange.fire({ elements: changed, removed: true }); } - remove(match: FileMatch): void { - this.doRemove(match); + remove(matches: FileMatch | FileMatch[]): void { + this.doRemove(matches); } replace(match: FileMatch): Promise { @@ -530,7 +530,7 @@ export class BaseFolderMatch extends Disposable { private onFileChange(fileMatch: FileMatch): void { let added: boolean = false; let removed: boolean = false; - if (!this._fileMatches.has(fileMatch.resource())) { + if (!this._fileMatches.has(fileMatch.resource)) { this.doAdd(fileMatch); added = true; } @@ -545,22 +545,28 @@ export class BaseFolderMatch extends Disposable { } private doAdd(fileMatch: FileMatch): void { - this._fileMatches.set(fileMatch.resource(), fileMatch); - if (this._unDisposedFileMatches.has(fileMatch.resource())) { - this._unDisposedFileMatches.delete(fileMatch.resource()); + this._fileMatches.set(fileMatch.resource, fileMatch); + if (this._unDisposedFileMatches.has(fileMatch.resource)) { + this._unDisposedFileMatches.delete(fileMatch.resource); } } - private doRemove(fileMatch: FileMatch, dispose: boolean = true, trigger: boolean = true): void { - this._fileMatches.delete(fileMatch.resource()); - if (dispose) { - fileMatch.dispose(); - } else { - this._unDisposedFileMatches.set(fileMatch.resource(), fileMatch); + private doRemove(fileMatches: FileMatch | FileMatch[], dispose: boolean = true, trigger: boolean = true): void { + if (!Array.isArray(fileMatches)) { + fileMatches = [fileMatches]; + } + + for (let match of fileMatches) { + this._fileMatches.delete(match.resource); + if (dispose) { + match.dispose(); + } else { + this._unDisposedFileMatches.set(match.resource, match); + } } if (trigger) { - this._onChange.fire({ elements: [fileMatch], removed: true }); + this._onChange.fire({ elements: fileMatches, removed: true }); } } @@ -590,7 +596,7 @@ export class FolderMatch extends BaseFolderMatch { super(_resource, _id, _index, _query, _parent, _searchModel, replaceService, instantiationService); } - resource(): URI { + get resource(): URI { return this._resource!; } } @@ -605,7 +611,7 @@ export function searchMatchComparer(elementA: RenderableMatch, elementB: Rendera } if (elementA instanceof FileMatch && elementB instanceof FileMatch) { - return elementA.resource().fsPath.localeCompare(elementB.resource().fsPath) || elementA.name().localeCompare(elementB.name()); + return elementA.resource.fsPath.localeCompare(elementB.resource.fsPath) || elementA.name().localeCompare(elementB.name()); } if (elementA instanceof Match && elementB instanceof Match) { @@ -652,7 +658,7 @@ export class SearchResult extends Disposable { .map(fq => fq.folder) .map((resource, index) => this.createFolderMatch(resource, resource.toString(), index, query)); - this._folderMatches.forEach(fm => this._folderMatchesMap.set(fm.resource().toString(), fm)); + this._folderMatches.forEach(fm => this._folderMatchesMap.set(fm.resource.toString(), fm)); this._otherFilesMatch = this.createOtherFilesFolderMatch('otherFiles', this._folderMatches.length + 1, query); this._query = query; @@ -686,26 +692,9 @@ export class SearchResult extends Disposable { add(allRaw: IFileMatch[], silent: boolean = false): void { // Split up raw into a list per folder so we can do a batch add per folder. - const rawPerFolder = new ResourceMap(); - const otherFileMatches: IFileMatch[] = []; - this._folderMatches.forEach(fm => rawPerFolder.set(fm.resource(), [])); - allRaw.forEach(rawFileMatch => { - const folderMatch = this.getFolderMatch(rawFileMatch.resource); - if (!folderMatch) { - // foldermatch was previously removed by user or disposed for some reason - return; - } - - const resource = folderMatch.resource(); - if (resource) { - rawPerFolder.get(resource)!.push(rawFileMatch); - } else { - otherFileMatches.push(rawFileMatch); - } - }); - - rawPerFolder.forEach((raw) => { + const { byFolder, other } = this.groupFilesByFolder(allRaw); + byFolder.forEach(raw => { if (!raw.length) { return; } @@ -716,7 +705,7 @@ export class SearchResult extends Disposable { } }); - this._otherFilesMatch!.add(otherFileMatches, silent); + this._otherFilesMatch!.add(other, silent); } clear(): void { @@ -724,16 +713,31 @@ export class SearchResult extends Disposable { this.disposeMatches(); } - remove(match: FileMatch | FolderMatch): void { - if (match instanceof FileMatch) { - this.getFolderMatch(match.resource()).remove(match); - } else { - match.clear(); + remove(matches: FileMatch | FileMatch[]): void { + if (!Array.isArray(matches)) { + matches = [matches]; + } + + const { byFolder, other } = this.groupFilesByFolder(matches); + byFolder.forEach(matches => { + if (!matches.length) { + return; + } + + this.getFolderMatch(matches[0].resource).remove(matches); + }); + + if (other.length) { + this.getFolderMatch(other[0].resource).remove(other); } } + removeFolder(match: FolderMatch): void { + match.clear(); + } + replace(match: FileMatch): Promise { - return this.getFolderMatch(match.resource()).replace(match); + return this.getFolderMatch(match.resource).replace(match); } replaceAll(progress: IProgress): Promise { @@ -807,7 +811,7 @@ export class SearchResult extends Disposable { if (this._showHighlights && selectedMatch) { // TS? this._rangeHighlightDecorations.highlightRange( - (selectedMatch).parent().resource(), + (selectedMatch).parent().resource, (selectedMatch).range() ); } else { @@ -830,6 +834,32 @@ export class SearchResult extends Disposable { }); } + private groupFilesByFolder(fileMatches: IFileMatch[]): { byFolder: ResourceMap, other: IFileMatch[] } { + const rawPerFolder = new ResourceMap(); + const otherFileMatches: IFileMatch[] = []; + this._folderMatches.forEach(fm => rawPerFolder.set(fm.resource, [])); + + fileMatches.forEach(rawFileMatch => { + const folderMatch = this.getFolderMatch(rawFileMatch.resource); + if (!folderMatch) { + // foldermatch was previously removed by user or disposed for some reason + return; + } + + const resource = folderMatch.resource; + if (resource) { + rawPerFolder.get(resource)!.push(rawFileMatch); + } else { + otherFileMatches.push(rawFileMatch); + } + }); + + return { + byFolder: rawPerFolder, + other: otherFileMatches + }; + } + private disposeMatches(): void { this.folderMatches().forEach(folderMatch => folderMatch.dispose()); this._folderMatches = []; diff --git a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts index 8f63fa9eb07..a2eb0ba8458 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts @@ -155,4 +155,4 @@ suite('Search Actions', () => { instantiationService.stub(IConfigurationService, new TestConfigurationService()); return instantiationService.createInstance(ModelServiceImpl); } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts index d1438b530b7..ba00d3b20a1 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -130,7 +130,7 @@ suite('SearchModel', () => { const actual = testObject.searchResult.matches(); assert.equal(2, actual.length); - assert.equal('file://c:/1', actual[0].resource().toString()); + assert.equal('file://c:/1', actual[0].resource.toString()); let actuaMatches = actual[0].matches(); assert.equal(2, actuaMatches.length); diff --git a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts index 64f09791842..b1a771cf4d0 100644 --- a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts @@ -55,12 +55,12 @@ suite('SearchResult', () => { test('File Match', function () { let fileMatch = aFileMatch('folder/file.txt'); assert.equal(fileMatch.matches(), 0); - assert.equal(fileMatch.resource().toString(), 'file:///folder/file.txt'); + assert.equal(fileMatch.resource.toString(), 'file:///folder/file.txt'); assert.equal(fileMatch.name(), 'file.txt'); fileMatch = aFileMatch('file.txt'); assert.equal(fileMatch.matches(), 0); - assert.equal(fileMatch.resource().toString(), 'file:///file.txt'); + assert.equal(fileMatch.resource.toString(), 'file:///file.txt'); assert.equal(fileMatch.name(), 'file.txt'); }); @@ -156,7 +156,7 @@ suite('SearchResult', () => { const actual = testObject.matches(); assert.equal(1, actual.length); - assert.equal('file://c:/', actual[0].resource().toString()); + assert.equal('file://c:/', actual[0].resource.toString()); const actuaMatches = actual[0].matches(); assert.equal(3, actuaMatches.length); @@ -186,7 +186,7 @@ suite('SearchResult', () => { const actual = testObject.matches(); assert.equal(2, actual.length); - assert.equal('file://c:/1', actual[0].resource().toString()); + assert.equal('file://c:/1', actual[0].resource.toString()); let actuaMatches = actual[0].matches(); assert.equal(2, actuaMatches.length); @@ -228,13 +228,30 @@ suite('SearchResult', () => { testObject.add([ aRawMatch('file://c:/1', new TextSearchMatch('preview 1', lineOneRange))]); - const objectRoRemove = testObject.matches()[0]; + const objectToRemove = testObject.matches()[0]; testObject.onChange(target); - testObject.remove(objectRoRemove); + testObject.remove(objectToRemove); assert.ok(target.calledOnce); - assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]); + assert.deepEqual([{ elements: [objectToRemove], removed: true }], target.args[0]); + }); + + test('remove array triggers change event', function () { + const target = sinon.spy(); + const testObject = aSearchResult(); + testObject.add([ + aRawMatch('file://c:/1', + new TextSearchMatch('preview 1', lineOneRange)), + aRawMatch('file://c:/2', + new TextSearchMatch('preview 2', lineOneRange))]); + const arrayToRemove = testObject.matches(); + testObject.onChange(target); + + testObject.remove(arrayToRemove); + + assert.ok(target.calledOnce); + assert.deepEqual([{ elements: arrayToRemove, removed: true }], target.args[0]); }); test('remove triggers change event', function () { @@ -243,13 +260,13 @@ suite('SearchResult', () => { testObject.add([ aRawMatch('file://c:/1', new TextSearchMatch('preview 1', lineOneRange))]); - const objectRoRemove = testObject.matches()[0]; + const objectToRemove = testObject.matches()[0]; testObject.onChange(target); - testObject.remove(objectRoRemove); + testObject.remove(objectToRemove); assert.ok(target.calledOnce); - assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]); + assert.deepEqual([{ elements: [objectToRemove], removed: true }], target.args[0]); }); test('Removing all line matches and adding back will add file back to result', function () { @@ -290,13 +307,13 @@ suite('SearchResult', () => { aRawMatch('file://c:/1', new TextSearchMatch('preview 1', lineOneRange))]); testObject.onChange(target); - const objectRoRemove = testObject.matches()[0]; + const objectToRemove = testObject.matches()[0]; - testObject.replace(objectRoRemove); + testObject.replace(objectToRemove); return voidPromise.then(() => { assert.ok(target.calledOnce); - assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]); + assert.deepEqual([{ elements: [objectToRemove], removed: true }], target.args[0]); }); }); diff --git a/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts b/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts index 5484d9f9a93..5c84fba2775 100644 --- a/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts +++ b/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts @@ -14,6 +14,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; interface ISnippetPick extends IQuickPickItem { snippet: Snippet; @@ -87,6 +88,7 @@ class InsertSnippetAction extends EditorAction { return undefined; } + const clipboardService = accessor.get(IClipboardService); const quickInputService = accessor.get(IQuickInputService); const { lineNumber, column } = editor.getPosition(); let { snippet, name, langId } = Args.fromUser(arg); @@ -165,9 +167,13 @@ class InsertSnippetAction extends EditorAction { } return quickInputService.pick(picks, { matchOnDetail: true }).then(pick => resolve(pick && pick.snippet), reject); } - }).then(snippet => { + }).then(async snippet => { + let clipboardText: string | undefined; + if (snippet.needsClipboard) { + clipboardText = await clipboardService.readText(); + } if (snippet) { - SnippetController2.get(editor).insert(snippet.codeSnippet, { overwriteBefore: 0, overwriteAfter: 0 }); + SnippetController2.get(editor).insert(snippet.codeSnippet, { clipboardText }); } }); } diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts index 8504522b3ef..89baf8b21e4 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts @@ -3,25 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from 'vs/nls'; import * as crypto from 'crypto'; import { onUnexpectedError } from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; -import { IFileService, IFileStat, IResolveFileResult } from 'vs/platform/files/common/files'; +import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IWindowConfiguration, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { endsWith } from 'vs/base/common/strings'; -import { Schemas } from 'vs/base/common/network'; -import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification'; -import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; -import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { joinPath } from 'vs/base/common/resources'; -import { ITextFileService, ITextFileContent } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, } from 'vs/workbench/services/textfile/common/textfiles'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService'; const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/; const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/; @@ -43,60 +36,6 @@ const SecondLevelDomainWhitelist = [ 'rhcloud.com', 'google.com' ]; -const ModulesToLookFor = [ - // Packages that suggest a node server - 'express', - 'sails', - 'koa', - 'hapi', - 'socket.io', - 'restify', - // JS frameworks - 'react', - 'react-native', - 'rnpm-plugin-windows', - '@angular/core', - '@ionic', - 'vue', - 'tns-core-modules', - // Other interesting packages - 'aws-sdk', - 'aws-amplify', - 'azure', - 'azure-storage', - 'firebase', - '@google-cloud/common', - 'heroku-cli' -]; -const PyModulesToLookFor = [ - 'azure', - 'azure-storage-common', - 'azure-storage-blob', - 'azure-storage-file', - 'azure-storage-queue', - 'azure-shell', - 'azure-cosmos', - 'azure-devtools', - 'azure-elasticluster', - 'azure-eventgrid', - 'azure-functions', - 'azure-graphrbac', - 'azure-keyvault', - 'azure-loganalytics', - 'azure-monitor', - 'azure-servicebus', - 'azure-servicefabric', - 'azure-storage', - 'azure-translator', - 'azure-iothub-device-client', - 'adal', - 'pydocumentdb', - 'botbuilder-core', - 'botbuilder-schema', - 'botframework-connector' -]; - -type Tags = { [index: string]: boolean | number | string | undefined }; function stripLowLevelDomains(domain: string): string | null { const match = domain.match(SecondLevelDomainMatcher); @@ -212,21 +151,14 @@ export function getHashedRemotesFromUri(workspaceUri: URI, fileService: IFileSer export class WorkspaceStats implements IWorkbenchContribution { - static TAGS: Tags; - - private static DISABLE_WORKSPACE_PROMPT_KEY = 'workspaces.dontPromptToOpen'; - constructor( @IFileService private readonly fileService: IFileService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IWindowService private readonly windowService: IWindowService, - @INotificationService private readonly notificationService: INotificationService, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @IStorageService private readonly storageService: IStorageService, @ITextFileService private readonly textFileService: ITextFileService, - @ISharedProcessService private readonly sharedProcessService: ISharedProcessService + @ISharedProcessService private readonly sharedProcessService: ISharedProcessService, + @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService ) { this.report(); } @@ -234,7 +166,7 @@ export class WorkspaceStats implements IWorkbenchContribution { private report(): void { // Workspace Stats - this.resolveWorkspaceTags(this.environmentService.configuration, rootFiles => this.handleWorkspaceFiles(rootFiles)) + this.workspaceStatsService.getTags() .then(tags => this.reportWorkspaceTags(tags), error => onUnexpectedError(error)); // Cloud Stats @@ -246,372 +178,7 @@ export class WorkspaceStats implements IWorkbenchContribution { diagnosticsChannel.call('reportWorkspaceStats', this.contextService.getWorkspace()); } - private static searchArray(arr: string[], regEx: RegExp): boolean | undefined { - return arr.some(v => v.search(regEx) > -1) || undefined; - } - /* __GDPR__FRAGMENT__ - "WorkspaceTags" : { - "workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "workspace.roots" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.empty" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.grunt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.gulp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.jake" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.tsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.jsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.config.xml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.vsc.extension" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.asp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.sln" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.unity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.express" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.sails" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.koa" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.hapi" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.socket.io" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.restify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.rnpm-plugin-windows" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.@angular/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.vue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.aws-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.aws-amplify-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.cordova.low" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.xamarin.android" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.xamarin.ios" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.android.cpp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.reactNative" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.ionic" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" }, - "workspace.nativeScript" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" }, - "workspace.java.pom" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.requirements" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.requirements.star" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.Pipfile" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.conda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.any-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-storage-common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-storage-blob" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-storage-file" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-storage-queue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-mgmt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-shell" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.pulumi-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-cosmos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-devtools" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-elasticluster" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-eventgrid" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-functions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-graphrbac" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-keyvault" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-loganalytics" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-monitor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-servicebus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-servicefabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-translator" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-iothub-device-client" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-ml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.azure-cognitiveservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.adal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - - } - */ - private resolveWorkspaceTags(configuration: IWindowConfiguration, participant?: (rootFiles: string[]) => void): Promise { - const tags: Tags = Object.create(null); - - const state = this.contextService.getWorkbenchState(); - const workspace = this.contextService.getWorkspace(); - - function createHash(uri: URI): string { - return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex'); - } - - let workspaceId: string | undefined; - switch (state) { - case WorkbenchState.EMPTY: - workspaceId = undefined; - break; - case WorkbenchState.FOLDER: - workspaceId = createHash(workspace.folders[0].uri); - break; - case WorkbenchState.WORKSPACE: - if (workspace.configuration) { - workspaceId = createHash(workspace.configuration); - } - } - - tags['workspace.id'] = workspaceId; - - const { filesToOpenOrCreate, filesToDiff } = configuration; - tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0; - tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0; - - const isEmpty = state === WorkbenchState.EMPTY; - tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length; - tags['workspace.empty'] = isEmpty; - - const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration); - if (!folders || !folders.length || !this.fileService) { - return Promise.resolve(tags); - } - - return this.fileService.resolveAll(folders.map(resource => ({ resource }))).then((files: IResolveFileResult[]) => { - const names = ([]).concat(...files.map(result => result.success ? (result.stat!.children || []) : [])).map(c => c.name); - const nameSet = names.reduce((s, n) => s.add(n.toLowerCase()), new Set()); - - if (participant) { - participant(names); - } - - tags['workspace.grunt'] = nameSet.has('gruntfile.js'); - tags['workspace.gulp'] = nameSet.has('gulpfile.js'); - tags['workspace.jake'] = nameSet.has('jakefile.js'); - - tags['workspace.tsconfig'] = nameSet.has('tsconfig.json'); - tags['workspace.jsconfig'] = nameSet.has('jsconfig.json'); - tags['workspace.config.xml'] = nameSet.has('config.xml'); - tags['workspace.vsc.extension'] = nameSet.has('vsc-extension-quickstart.md'); - - tags['workspace.ASP5'] = nameSet.has('project.json') && WorkspaceStats.searchArray(names, /^.+\.cs$/i); - tags['workspace.sln'] = WorkspaceStats.searchArray(names, /^.+\.sln$|^.+\.csproj$/i); - tags['workspace.unity'] = nameSet.has('assets') && nameSet.has('library') && nameSet.has('projectsettings'); - tags['workspace.npm'] = nameSet.has('package.json') || nameSet.has('node_modules'); - tags['workspace.bower'] = nameSet.has('bower.json') || nameSet.has('bower_components'); - - tags['workspace.java.pom'] = nameSet.has('pom.xml'); - - tags['workspace.yeoman.code.ext'] = nameSet.has('vsc-extension-quickstart.md'); - - tags['workspace.py.requirements'] = nameSet.has('requirements.txt'); - tags['workspace.py.requirements.star'] = WorkspaceStats.searchArray(names, /^(.*)requirements(.*)\.txt$/i); - tags['workspace.py.Pipfile'] = nameSet.has('pipfile'); - tags['workspace.py.conda'] = WorkspaceStats.searchArray(names, /^environment(\.yml$|\.yaml$)/i); - - const mainActivity = nameSet.has('mainactivity.cs') || nameSet.has('mainactivity.fs'); - const appDelegate = nameSet.has('appdelegate.cs') || nameSet.has('appdelegate.fs'); - const androidManifest = nameSet.has('androidmanifest.xml'); - - const platforms = nameSet.has('platforms'); - const plugins = nameSet.has('plugins'); - const www = nameSet.has('www'); - const properties = nameSet.has('properties'); - const resources = nameSet.has('resources'); - const jni = nameSet.has('jni'); - - if (tags['workspace.config.xml'] && - !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) { - if (platforms && plugins && www) { - tags['workspace.cordova.high'] = true; - } else { - tags['workspace.cordova.low'] = true; - } - } - - if (tags['workspace.config.xml'] && - !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) { - - if (nameSet.has('ionic.config.json')) { - tags['workspace.ionic'] = true; - } - } - - if (mainActivity && properties && resources) { - tags['workspace.xamarin.android'] = true; - } - - if (appDelegate && resources) { - tags['workspace.xamarin.ios'] = true; - } - - if (androidManifest && jni) { - tags['workspace.android.cpp'] = true; - } - - function getFilePromises(filename: string, fileService: IFileService, textFileService: ITextFileService, contentHandler: (content: ITextFileContent) => void): Promise[] { - return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => { - const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` }); - return fileService.exists(uri).then(exists => { - if (!exists) { - return undefined; - } - - return textFileService.read(uri, { acceptTextOnly: true }).then(contentHandler); - }, err => { - // Ignore missing file - }); - }); - } - - function addPythonTags(packageName: string): void { - if (PyModulesToLookFor.indexOf(packageName) > -1) { - tags['workspace.py.' + packageName] = true; - } - // cognitive services has a lot of tiny packages. e.g. 'azure-cognitiveservices-search-autosuggest' - if (packageName.indexOf('azure-cognitiveservices') > -1) { - tags['workspace.py.azure-cognitiveservices'] = true; - } - if (packageName.indexOf('azure-mgmt') > -1) { - tags['workspace.py.azure-mgmt'] = true; - } - if (packageName.indexOf('azure-ml') > -1) { - tags['workspace.py.azure-ml'] = true; - } - if (!tags['workspace.py.any-azure']) { - tags['workspace.py.any-azure'] = /azure/i.test(packageName); - } - } - - const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, this.textFileService, content => { - const dependencies: string[] = content.value.split(/\r\n|\r|\n/); - for (let dependency of dependencies) { - // Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo` - const format1 = dependency.split('=='); - const format2 = dependency.split('>='); - const packageName = (format1.length === 2 ? format1[0] : format2[0]).trim(); - addPythonTags(packageName); - } - }); - - const pipfilePromises = getFilePromises('pipfile', this.fileService, this.textFileService, content => { - let dependencies: string[] = content.value.split(/\r\n|\r|\n/); - - // We're only interested in the '[packages]' section of the Pipfile - dependencies = dependencies.slice(dependencies.indexOf('[packages]') + 1); - - for (let dependency of dependencies) { - if (dependency.trim().indexOf('[') > -1) { - break; - } - // All dependencies in Pipfiles follow the format: ` = ` - if (dependency.indexOf('=') === -1) { - continue; - } - const packageName = dependency.split('=')[0].trim(); - addPythonTags(packageName); - } - - }); - - const packageJsonPromises = getFilePromises('package.json', this.fileService, this.textFileService, content => { - try { - const packageJsonContents = JSON.parse(content.value); - let dependencies = packageJsonContents['dependencies']; - let devDependencies = packageJsonContents['devDependencies']; - for (let module of ModulesToLookFor) { - if ('react-native' === module) { - if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) { - tags['workspace.reactNative'] = true; - } - } else if ('tns-core-modules' === module) { - if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) { - tags['workspace.nativescript'] = true; - } - } else { - if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) { - tags['workspace.npm.' + module] = true; - } - } - } - - } - catch (e) { - // Ignore errors when resolving file or parsing file contents - } - }); - return Promise.all([...packageJsonPromises, ...requirementsTxtPromises, ...pipfilePromises]).then(() => tags); - }); - } - - private handleWorkspaceFiles(rootFiles: string[]): void { - const state = this.contextService.getWorkbenchState(); - const workspace = this.contextService.getWorkspace(); - - // Handle top-level workspace files for local single folder workspace - if (state === WorkbenchState.FOLDER) { - const workspaceFiles = rootFiles.filter(hasWorkspaceFileExtension); - if (workspaceFiles.length > 0) { - this.doHandleWorkspaceFiles(workspace.folders[0].uri, workspaceFiles); - } - } - } - - private doHandleWorkspaceFiles(folder: URI, workspaces: string[]): void { - if (this.storageService.getBoolean(WorkspaceStats.DISABLE_WORKSPACE_PROMPT_KEY, StorageScope.WORKSPACE)) { - return; // prompt disabled by user - } - - const doNotShowAgain: IPromptChoice = { - label: localize('never again', "Don't Show Again"), - isSecondary: true, - run: () => this.storageService.store(WorkspaceStats.DISABLE_WORKSPACE_PROMPT_KEY, true, StorageScope.WORKSPACE) - }; - - // Prompt to open one workspace - if (workspaces.length === 1) { - const workspaceFile = workspaces[0]; - - this.notificationService.prompt(Severity.Info, localize('workspaceFound', "This folder contains a workspace file '{0}'. Do you want to open it? [Learn more]({1}) about workspace files.", workspaceFile, 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{ - label: localize('openWorkspace', "Open Workspace"), - run: () => this.windowService.openWindow([{ workspaceUri: joinPath(folder, workspaceFile) }]) - }, doNotShowAgain]); - } - - // Prompt to select a workspace from many - else if (workspaces.length > 1) { - this.notificationService.prompt(Severity.Info, localize('workspacesFound', "This folder contains multiple workspace files. Do you want to open one? [Learn more]({0}) about workspace files.", 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{ - label: localize('selectWorkspace', "Select Workspace"), - run: () => { - this.quickInputService.pick( - workspaces.map(workspace => ({ label: workspace } as IQuickPickItem)), - { placeHolder: localize('selectToOpen', "Select a workspace to open") }).then(pick => { - if (pick) { - this.windowService.openWindow([{ workspaceUri: joinPath(folder, pick.label) }]); - } - }); - } - }, doNotShowAgain]); - } - } - - private findFolders(configuration: IWindowConfiguration): URI[] | undefined { - const folder = this.findFolder(configuration); - return folder && [folder]; - } - - private findFolder({ filesToOpenOrCreate, filesToDiff }: IWindowConfiguration): URI | undefined { - if (filesToOpenOrCreate && filesToOpenOrCreate.length) { - return this.parentURI(filesToOpenOrCreate[0].fileUri); - } else if (filesToDiff && filesToDiff.length) { - return this.parentURI(filesToDiff[0].fileUri); - } - return undefined; - } - - private parentURI(uri: URI | undefined): URI | undefined { - if (!uri) { - return undefined; - } - const path = uri.path; - const i = path.lastIndexOf('/'); - return i !== -1 ? uri.with({ path: path.substr(0, i) }) : undefined; - } private reportWorkspaceTags(tags: Tags): void { /* __GDPR__ @@ -622,7 +189,6 @@ export class WorkspaceStats implements IWorkbenchContribution { } */ this.telemetryService.publicLog('workspce.tags', tags); - WorkspaceStats.TAGS = tags; } private reportRemoteDomains(workspaceUris: URI[]): void { @@ -689,6 +255,10 @@ export class WorkspaceStats implements IWorkbenchContribution { }); } + private static searchArray(arr: string[], regEx: RegExp): boolean | undefined { + return arr.some(v => v.search(regEx) > -1) || undefined; + } + /* __GDPR__FRAGMENT__ "AzureTags" : { "java" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } @@ -749,12 +319,10 @@ export class WorkspaceStats implements IWorkbenchContribution { if (['DIRECT', 'PROXY', 'HTTPS', 'SOCKS', 'EMPTY'].indexOf(type) === -1) { type = 'UNKNOWN'; } - /* __GDPR__ - "resolveProxy.stats" : { - "type": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('resolveProxy.stats', { type }); + type ResolveProxyStatsClassification = { + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + this.telemetryService.publicLog2<{ type: String }, ResolveProxyStatsClassification>('resolveProxy.stats', { type }); }).then(undefined, onUnexpectedError); } } diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts new file mode 100644 index 00000000000..ef0dc08081c --- /dev/null +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -0,0 +1,505 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as crypto from 'crypto'; +import { IFileService, IResolveFileResult, IFileStat } from 'vs/platform/files/common/files'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { ITextFileService, ITextFileContent } from 'vs/workbench/services/textfile/common/textfiles'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; +import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; +import { localize } from 'vs/nls'; +import Severity from 'vs/base/common/severity'; +import { joinPath } from 'vs/base/common/resources'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export type Tags = { [index: string]: boolean | number | string | undefined }; + +const DISABLE_WORKSPACE_PROMPT_KEY = 'workspaces.dontPromptToOpen'; + +const ModulesToLookFor = [ + // Packages that suggest a node server + 'express', + 'sails', + 'koa', + 'hapi', + 'socket.io', + 'restify', + // JS frameworks + 'react', + 'react-native', + 'rnpm-plugin-windows', + '@angular/core', + '@ionic', + 'vue', + 'tns-core-modules', + // Other interesting packages + 'aws-sdk', + 'aws-amplify', + 'azure', + 'azure-storage', + 'firebase', + '@google-cloud/common', + 'heroku-cli', + //Office and Sharepoint packages + '@microsoft/office-js', + '@microsoft/office-js-helpers', + '@types/office-js', + '@types/office-runtime', + 'office-ui-fabric-react', + '@uifabric/icons', + '@uifabric/merge-styles', + '@uifabric/styling', + '@uifabric/experiments', + '@uifabric/utilities', + '@microsoft/rush', + 'lerna', + 'just-task', + 'beachball' +]; +const PyModulesToLookFor = [ + 'azure', + 'azure-storage-common', + 'azure-storage-blob', + 'azure-storage-file', + 'azure-storage-queue', + 'azure-shell', + 'azure-cosmos', + 'azure-devtools', + 'azure-elasticluster', + 'azure-eventgrid', + 'azure-functions', + 'azure-graphrbac', + 'azure-keyvault', + 'azure-loganalytics', + 'azure-monitor', + 'azure-servicebus', + 'azure-servicefabric', + 'azure-storage', + 'azure-translator', + 'azure-iothub-device-client', + 'adal', + 'pydocumentdb', + 'botbuilder-core', + 'botbuilder-schema', + 'botframework-connector' +]; + +export const IWorkspaceStatsService = createDecorator('workspaceStatsService'); + +export interface IWorkspaceStatsService { + _serviceBrand: any; + getTags(): Promise; +} + + +export class WorkspaceStatsService implements IWorkspaceStatsService { + _serviceBrand: any; + private _tags: Tags; + + constructor( + @IFileService private readonly fileService: IFileService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IWindowService private readonly windowService: IWindowService, + @INotificationService private readonly notificationService: INotificationService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IStorageService private readonly storageService: IStorageService, + @ITextFileService private readonly textFileService: ITextFileService + ) { } + + public async getTags(): Promise { + if (!this._tags) { + this._tags = await this.resolveWorkspaceTags(this.environmentService.configuration, rootFiles => this.handleWorkspaceFiles(rootFiles)); + } + + return this._tags; + } + + /* __GDPR__FRAGMENT__ + "WorkspaceTags" : { + "workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workspace.roots" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.empty" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.grunt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.gulp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.jake" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.tsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.jsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.config.xml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.vsc.extension" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.asp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.sln" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.unity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.express" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.sails" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.koa" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.hapi" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.socket.io" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.restify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.rnpm-plugin-windows" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@angular/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.vue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.aws-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.aws-amplify-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js-helpers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-runtime" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.office-ui-fabric-react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/icons" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/merge-styles" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/styling" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/experiments" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/utilities" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/rush" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.lerna" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.just-task" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.beachball" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.cordova.low" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.xamarin.android" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.xamarin.ios" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.android.cpp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.reactNative" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.ionic" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" }, + "workspace.nativeScript" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" }, + "workspace.java.pom" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.requirements" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.requirements.star" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.Pipfile" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.conda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.any-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-storage-common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-storage-blob" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-storage-file" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-storage-queue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-mgmt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-shell" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.pulumi-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-cosmos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-devtools" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-elasticluster" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-eventgrid" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-functions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-graphrbac" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-keyvault" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-loganalytics" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-monitor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-servicebus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-servicefabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-translator" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-iothub-device-client" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-ml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.azure-cognitiveservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.adal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + } + */ + private resolveWorkspaceTags(configuration: IWindowConfiguration, participant?: (rootFiles: string[]) => void): Promise { + const tags: Tags = Object.create(null); + + const state = this.contextService.getWorkbenchState(); + const workspace = this.contextService.getWorkspace(); + + function createHash(uri: URI): string { + return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex'); + } + + let workspaceId: string | undefined; + switch (state) { + case WorkbenchState.EMPTY: + workspaceId = undefined; + break; + case WorkbenchState.FOLDER: + workspaceId = createHash(workspace.folders[0].uri); + break; + case WorkbenchState.WORKSPACE: + if (workspace.configuration) { + workspaceId = createHash(workspace.configuration); + } + } + + tags['workspace.id'] = workspaceId; + + const { filesToOpenOrCreate, filesToDiff } = configuration; + tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0; + tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0; + + const isEmpty = state === WorkbenchState.EMPTY; + tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length; + tags['workspace.empty'] = isEmpty; + + const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration); + if (!folders || !folders.length || !this.fileService) { + return Promise.resolve(tags); + } + + return this.fileService.resolveAll(folders.map(resource => ({ resource }))).then((files: IResolveFileResult[]) => { + const names = ([]).concat(...files.map(result => result.success ? (result.stat!.children || []) : [])).map(c => c.name); + const nameSet = names.reduce((s, n) => s.add(n.toLowerCase()), new Set()); + + if (participant) { + participant(names); + } + + tags['workspace.grunt'] = nameSet.has('gruntfile.js'); + tags['workspace.gulp'] = nameSet.has('gulpfile.js'); + tags['workspace.jake'] = nameSet.has('jakefile.js'); + + tags['workspace.tsconfig'] = nameSet.has('tsconfig.json'); + tags['workspace.jsconfig'] = nameSet.has('jsconfig.json'); + tags['workspace.config.xml'] = nameSet.has('config.xml'); + tags['workspace.vsc.extension'] = nameSet.has('vsc-extension-quickstart.md'); + + tags['workspace.ASP5'] = nameSet.has('project.json') && this.searchArray(names, /^.+\.cs$/i); + tags['workspace.sln'] = this.searchArray(names, /^.+\.sln$|^.+\.csproj$/i); + tags['workspace.unity'] = nameSet.has('assets') && nameSet.has('library') && nameSet.has('projectsettings'); + tags['workspace.npm'] = nameSet.has('package.json') || nameSet.has('node_modules'); + tags['workspace.bower'] = nameSet.has('bower.json') || nameSet.has('bower_components'); + + tags['workspace.java.pom'] = nameSet.has('pom.xml'); + + tags['workspace.yeoman.code.ext'] = nameSet.has('vsc-extension-quickstart.md'); + + tags['workspace.py.requirements'] = nameSet.has('requirements.txt'); + tags['workspace.py.requirements.star'] = this.searchArray(names, /^(.*)requirements(.*)\.txt$/i); + tags['workspace.py.Pipfile'] = nameSet.has('pipfile'); + tags['workspace.py.conda'] = this.searchArray(names, /^environment(\.yml$|\.yaml$)/i); + + const mainActivity = nameSet.has('mainactivity.cs') || nameSet.has('mainactivity.fs'); + const appDelegate = nameSet.has('appdelegate.cs') || nameSet.has('appdelegate.fs'); + const androidManifest = nameSet.has('androidmanifest.xml'); + + const platforms = nameSet.has('platforms'); + const plugins = nameSet.has('plugins'); + const www = nameSet.has('www'); + const properties = nameSet.has('properties'); + const resources = nameSet.has('resources'); + const jni = nameSet.has('jni'); + + if (tags['workspace.config.xml'] && + !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) { + if (platforms && plugins && www) { + tags['workspace.cordova.high'] = true; + } else { + tags['workspace.cordova.low'] = true; + } + } + + if (tags['workspace.config.xml'] && + !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) { + + if (nameSet.has('ionic.config.json')) { + tags['workspace.ionic'] = true; + } + } + + if (mainActivity && properties && resources) { + tags['workspace.xamarin.android'] = true; + } + + if (appDelegate && resources) { + tags['workspace.xamarin.ios'] = true; + } + + if (androidManifest && jni) { + tags['workspace.android.cpp'] = true; + } + + function getFilePromises(filename: string, fileService: IFileService, textFileService: ITextFileService, contentHandler: (content: ITextFileContent) => void): Promise[] { + return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => { + const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` }); + return fileService.exists(uri).then(exists => { + if (!exists) { + return undefined; + } + + return textFileService.read(uri, { acceptTextOnly: true }).then(contentHandler); + }, err => { + // Ignore missing file + }); + }); + } + + function addPythonTags(packageName: string): void { + if (PyModulesToLookFor.indexOf(packageName) > -1) { + tags['workspace.py.' + packageName] = true; + } + // cognitive services has a lot of tiny packages. e.g. 'azure-cognitiveservices-search-autosuggest' + if (packageName.indexOf('azure-cognitiveservices') > -1) { + tags['workspace.py.azure-cognitiveservices'] = true; + } + if (packageName.indexOf('azure-mgmt') > -1) { + tags['workspace.py.azure-mgmt'] = true; + } + if (packageName.indexOf('azure-ml') > -1) { + tags['workspace.py.azure-ml'] = true; + } + if (!tags['workspace.py.any-azure']) { + tags['workspace.py.any-azure'] = /azure/i.test(packageName); + } + } + + const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, this.textFileService, content => { + const dependencies: string[] = content.value.split(/\r\n|\r|\n/); + for (let dependency of dependencies) { + // Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo` + const format1 = dependency.split('=='); + const format2 = dependency.split('>='); + const packageName = (format1.length === 2 ? format1[0] : format2[0]).trim(); + addPythonTags(packageName); + } + }); + + const pipfilePromises = getFilePromises('pipfile', this.fileService, this.textFileService, content => { + let dependencies: string[] = content.value.split(/\r\n|\r|\n/); + + // We're only interested in the '[packages]' section of the Pipfile + dependencies = dependencies.slice(dependencies.indexOf('[packages]') + 1); + + for (let dependency of dependencies) { + if (dependency.trim().indexOf('[') > -1) { + break; + } + // All dependencies in Pipfiles follow the format: ` = ` + if (dependency.indexOf('=') === -1) { + continue; + } + const packageName = dependency.split('=')[0].trim(); + addPythonTags(packageName); + } + + }); + + const packageJsonPromises = getFilePromises('package.json', this.fileService, this.textFileService, content => { + try { + const packageJsonContents = JSON.parse(content.value); + let dependencies = packageJsonContents['dependencies']; + let devDependencies = packageJsonContents['devDependencies']; + for (let module of ModulesToLookFor) { + if ('react-native' === module) { + if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) { + tags['workspace.reactNative'] = true; + } + } else if ('tns-core-modules' === module) { + if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) { + tags['workspace.nativescript'] = true; + } + } else { + if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) { + tags['workspace.npm.' + module] = true; + } + } + } + + } + catch (e) { + // Ignore errors when resolving file or parsing file contents + } + }); + return Promise.all([...packageJsonPromises, ...requirementsTxtPromises, ...pipfilePromises]).then(() => tags); + }); + } + + private handleWorkspaceFiles(rootFiles: string[]): void { + const state = this.contextService.getWorkbenchState(); + const workspace = this.contextService.getWorkspace(); + + // Handle top-level workspace files for local single folder workspace + if (state === WorkbenchState.FOLDER) { + const workspaceFiles = rootFiles.filter(hasWorkspaceFileExtension); + if (workspaceFiles.length > 0) { + this.doHandleWorkspaceFiles(workspace.folders[0].uri, workspaceFiles); + } + } + } + + private doHandleWorkspaceFiles(folder: URI, workspaces: string[]): void { + if (this.storageService.getBoolean(DISABLE_WORKSPACE_PROMPT_KEY, StorageScope.WORKSPACE)) { + return; // prompt disabled by user + } + + const doNotShowAgain: IPromptChoice = { + label: localize('never again', "Don't Show Again"), + isSecondary: true, + run: () => this.storageService.store(DISABLE_WORKSPACE_PROMPT_KEY, true, StorageScope.WORKSPACE) + }; + + // Prompt to open one workspace + if (workspaces.length === 1) { + const workspaceFile = workspaces[0]; + + this.notificationService.prompt(Severity.Info, localize('workspaceFound', "This folder contains a workspace file '{0}'. Do you want to open it? [Learn more]({1}) about workspace files.", workspaceFile, 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{ + label: localize('openWorkspace', "Open Workspace"), + run: () => this.windowService.openWindow([{ workspaceUri: joinPath(folder, workspaceFile) }]) + }, doNotShowAgain]); + } + + // Prompt to select a workspace from many + else if (workspaces.length > 1) { + this.notificationService.prompt(Severity.Info, localize('workspacesFound', "This folder contains multiple workspace files. Do you want to open one? [Learn more]({0}) about workspace files.", 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{ + label: localize('selectWorkspace', "Select Workspace"), + run: () => { + this.quickInputService.pick( + workspaces.map(workspace => ({ label: workspace } as IQuickPickItem)), + { placeHolder: localize('selectToOpen', "Select a workspace to open") }).then(pick => { + if (pick) { + this.windowService.openWindow([{ workspaceUri: joinPath(folder, pick.label) }]); + } + }); + } + }, doNotShowAgain]); + } + } + + private findFolders(configuration: IWindowConfiguration): URI[] | undefined { + const folder = this.findFolder(configuration); + return folder && [folder]; + } + + private findFolder({ filesToOpenOrCreate, filesToDiff }: IWindowConfiguration): URI | undefined { + if (filesToOpenOrCreate && filesToOpenOrCreate.length) { + return this.parentURI(filesToOpenOrCreate[0].fileUri); + } else if (filesToDiff && filesToDiff.length) { + return this.parentURI(filesToDiff[0].fileUri); + } + return undefined; + } + + private parentURI(uri: URI | undefined): URI | undefined { + if (!uri) { + return undefined; + } + const path = uri.path; + const i = path.lastIndexOf('/'); + return i !== -1 ? uri.with({ path: path.substr(0, i) }) : undefined; + } + + private searchArray(arr: string[], regEx: RegExp): boolean | undefined { + return arr.some(v => v.search(regEx) > -1) || undefined; + } +} diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 310040325d7..894a0b10e7a 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"); @@ -472,7 +470,17 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._taskSystem.customExecutionComplete(task, result); } + private isBadTsConfig(taskId: string | TaskIdentifier | undefined): taskId is string { + const badTsconfig = '\\tsconfig.json'; + const tsc = 'tsc'; + return typeof taskId === 'string' && (taskId.length > badTsconfig.length) && strings.equalsIgnoreCase(taskId.substring(taskId.length - badTsconfig.length, taskId.length), badTsconfig) && (taskId.substring(0, tsc.length) === tsc); + } + public getTask(folder: IWorkspaceFolder | string, identifier: string | TaskIdentifier, compareId: boolean = false): Promise { + if (this.isBadTsConfig(identifier)) { + return Promise.reject(new Error(nls.localize('badTsConfig', "Task '{0}' contains \"\\\\\". Typescript tasks must use \"/\"", identifier))); + } + const name = Types.isString(folder) ? folder : folder.name; if (this.ignoredWorkspaceFolders.some(ignored => ignored.name === name)) { return Promise.reject(new Error(nls.localize('TaskServer.folderIgnored', 'The folder {0} is ignored since it uses task version 0.1.0', name))); @@ -2047,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/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 3dc54054450..efef7a28135 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -14,7 +14,7 @@ import { IStringDictionary, values } from 'vs/base/common/collections'; import { LinkedMap, Touch } from 'vs/base/common/map'; import Severity from 'vs/base/common/severity'; import { Event, Emitter } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { isUNC } from 'vs/base/common/extpath'; import { IFileService } from 'vs/platform/files/common/files'; @@ -473,7 +473,7 @@ export class TerminalTaskSystem implements ITaskSystem { return resolvedVariables.then((resolvedVariables) => { const isCustomExecution = (task.command.runtime === RuntimeType.CustomExecution) || (task.command.runtime === RuntimeType.CustomExecution2); - if (resolvedVariables && task.command && task.command.runtime && (isCustomExecution || task.command.name)) { + if (resolvedVariables && (task.command !== undefined) && task.command.runtime && (isCustomExecution || (task.command.name !== undefined))) { this.currentTask.resolvedVariables = resolvedVariables; return this.executeInTerminal(task, trigger, new VariableResolver(workspaceFolder, systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder); } else { @@ -518,9 +518,9 @@ export class TerminalTaskSystem implements ITaskSystem { if (task.configurationProperties.isBackground) { const problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService, this.fileService); - let toDispose: IDisposable[] | undefined = []; + const toDispose = new DisposableStore(); let eventCounter: number = 0; - toDispose.push(watchingProblemMatcher.onDidStateChange((event) => { + toDispose.add(watchingProblemMatcher.onDidStateChange((event) => { if (event.kind === ProblemCollectorEventKind.BackgroundProcessingBegins) { eventCounter++; this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task)); @@ -618,8 +618,7 @@ export class TerminalTaskSystem implements ITaskSystem { } eventCounter = 0; this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.End, task)); - toDispose = dispose(toDispose!); - toDispose = undefined; + toDispose.dispose(); resolve({ exitCode }); }); }); @@ -927,7 +926,7 @@ export class TerminalTaskSystem implements ITaskSystem { }; } else if (task.command.runtime === RuntimeType.CustomExecution2) { this.currentTask.shellLaunchConfig = launchConfigs = { - isVirtualProcess: true, + isExtensionTerminal: true, waitOnExit, name: this.createTerminalName(task, workspaceFolder), initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined diff --git a/src/vs/workbench/contrib/tasks/common/problemMatcher.ts b/src/vs/workbench/contrib/tasks/common/problemMatcher.ts index 30c10b277a6..1c4f457c5b9 100644 --- a/src/vs/workbench/contrib/tasks/common/problemMatcher.ts +++ b/src/vs/workbench/contrib/tasks/common/problemMatcher.ts @@ -1718,7 +1718,7 @@ class ProblemMatcherRegistryImpl implements IProblemMatcherRegistry { private matchers: IStringDictionary; private readyPromise: Promise; private readonly _onMatchersChanged: Emitter = new Emitter(); - public get onMatcherChanged(): Event { return this._onMatchersChanged.event; } + public readonly onMatcherChanged: Event = this._onMatchersChanged.event; constructor() { diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index 528b95b0134..4e856c3b65c 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -289,7 +289,7 @@ export interface ConfigurationProperties { label?: string; /** - * An optional indentifier which can be used to reference a task + * An optional identifier which can be used to reference a task * in a dependsOn or other attributes. */ identifier?: string; @@ -432,7 +432,7 @@ export interface BaseTaskRunnerConfiguration { taskSelector?: string; /** - * The problem matcher(s) to used if a global command is exucuted (e.g. no tasks + * The problem matcher(s) to used if a global command is executed (e.g. no tasks * are defined). A tasks.json file can either contain a global problemMatcher * property or a tasks property but not both. */ @@ -503,7 +503,7 @@ export interface ExternalTaskRunnerConfiguration extends BaseTaskRunnerConfigura osx?: BaseTaskRunnerConfiguration; /** - * Linux speciif task configuration + * Linux specific task configuration */ linux?: BaseTaskRunnerConfiguration; } @@ -913,13 +913,13 @@ namespace CommandConfiguration { } } - interface BaseCommandConfiguationShape extends BaseCommandProperties, LegacyCommandProperties { + interface BaseCommandConfigurationShape extends BaseCommandProperties, LegacyCommandProperties { } - interface CommandConfiguationShape extends BaseCommandConfiguationShape { - windows?: BaseCommandConfiguationShape; - osx?: BaseCommandConfiguationShape; - linux?: BaseCommandConfiguationShape; + interface CommandConfigurationShape extends BaseCommandConfigurationShape { + windows?: BaseCommandConfigurationShape; + osx?: BaseCommandConfigurationShape; + linux?: BaseCommandConfigurationShape; } const properties: MetaData[] = [ @@ -928,7 +928,7 @@ namespace CommandConfiguration { { property: 'presentation', type: PresentationOptions } ]; - export function from(this: void, config: CommandConfiguationShape, context: ParseContext): Tasks.CommandConfiguration | undefined { + export function from(this: void, config: CommandConfigurationShape, context: ParseContext): Tasks.CommandConfiguration | undefined { let result: Tasks.CommandConfiguration = fromBase(config, context)!; let osConfig: Tasks.CommandConfiguration | undefined = undefined; @@ -945,7 +945,7 @@ namespace CommandConfiguration { return isEmpty(result) ? undefined : result; } - function fromBase(this: void, config: BaseCommandConfiguationShape, context: ParseContext): Tasks.CommandConfiguration | undefined { + function fromBase(this: void, config: BaseCommandConfigurationShape, context: ParseContext): Tasks.CommandConfiguration | undefined { let name: Tasks.CommandString | undefined = ShellString.from(config.command); let runtime: Tasks.RuntimeType; if (Types.isString(config.type)) { @@ -1172,7 +1172,7 @@ namespace ProblemMatcherConverter { return localProblemMatcher; } } - context.taskLoadIssues.push(nls.localize('ConfigurationParser.invalidVaraibleReference', 'Error: Invalid problemMatcher reference: {0}\n', value)); + context.taskLoadIssues.push(nls.localize('ConfigurationParser.invalidVariableReference', 'Error: Invalid problemMatcher reference: {0}\n', value)); return undefined; } else { let json = value; diff --git a/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts b/src/vs/workbench/contrib/tasks/electron-browser/taskService.ts index 631275db0d0..decffe55e63 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 3e73903b7d2..35c131834e0 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/terminal/browser/addons/navigationModeAddon.ts b/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts new file mode 100644 index 00000000000..74542173298 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { Terminal, ITerminalAddon } from 'xterm'; +import { addDisposableListener } from 'vs/base/browser/dom'; +import { INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal'; + +export class NavigationModeAddon implements INavigationMode, ITerminalAddon { + private _terminal: Terminal; + + constructor( + private _navigationModeContextKey: IContextKey + ) { } + + activate(terminal: Terminal): void { + this._terminal = terminal; + } + + dispose() { } + + exitNavigationMode(): void { + this._terminal.scrollToBottom(); + this._terminal.focus(); + } + + focusPreviousLine(): void { + // Focus previous row if a row is already focused + if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) { + const element = document.activeElement.previousElementSibling; + if (element) { + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } + return; + } + + // Ensure a11y tree exists + const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree'); + if (!treeContainer) { + return; + } + + // Target is row before the cursor + const targetRow = Math.max(this._terminal.buffer.cursorY - 1, 0); + + // Check bounds + if (treeContainer.childElementCount < targetRow) { + return; + } + + // Focus + const element = treeContainer.childNodes.item(targetRow); + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } + + focusNextLine(): void { + // Focus previous row if a row is already focused + if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) { + const element = document.activeElement.nextElementSibling; + if (element) { + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } + return; + } + + // Ensure a11y tree exists + const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree'); + if (!treeContainer) { + return; + } + + // Target is cursor row + const targetRow = this._terminal.buffer.cursorY; + + // Check bounds + if (treeContainer.childElementCount < targetRow) { + return; + } + + // Focus row before cursor + const element = treeContainer.childNodes.item(targetRow); + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 14a1be7a866..08fc487af2f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -20,10 +20,10 @@ import * as panel from 'vs/workbench/browser/panel'; import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { Extensions as QuickOpenExtensions, IQuickOpenRegistry, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; -import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions'; +import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand, NavigationModeFocusPreviousTerminalAction, NavigationModeFocusNextTerminalAction, NavigationModeExitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; -import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; +import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS } from 'vs/workbench/contrib/terminal/common/terminal'; import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; @@ -33,6 +33,7 @@ import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/br import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig'; +import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; registerSingleton(ITerminalService, TerminalService, true); @@ -459,6 +460,21 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextComm primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeExitTerminalAction, NavigationModeExitTerminalAction.ID, NavigationModeExitTerminalAction.LABEL, { + primary: KeyCode.Escape +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Exit Navigation Mode', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.UpArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.UpArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.DownArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.DownArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 057a5df5631..23077803ab1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -159,10 +159,10 @@ export class CopyTerminalSelectionAction extends Action { super(id, label); } - public run(event?: any): Promise { + public async run(event?: any): Promise { const terminalInstance = this.terminalService.getActiveInstance(); if (terminalInstance) { - terminalInstance.copySelection(); + await terminalInstance.copySelection(); } return Promise.resolve(undefined); } @@ -607,12 +607,11 @@ export class TerminalPasteAction extends Action { super(id, label); } - public run(event?: any): Promise { + public async run(event?: any): Promise { const instance = this.terminalService.getActiveOrCreateInstance(); if (instance) { - instance.paste(); + await instance.paste(); } - return Promise.resolve(undefined); } } @@ -749,6 +748,7 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem { this._register(terminalService.onInstancesChanged(this._updateItems, this)); this._register(terminalService.onActiveTabChanged(this._updateItems, this)); this._register(terminalService.onInstanceTitleChanged(this._updateItems, this)); + this._register(terminalService.onTabDisposed(this._updateItems, this)); this._register(attachSelectBoxStyler(this.selectBox, themeService)); } @@ -886,6 +886,71 @@ export class ScrollToTopTerminalAction extends Action { } } +export class NavigationModeExitTerminalAction extends Action { + + public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT; + public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeExit', "Exit Navigation Mode"); + + constructor( + id: string, label: string, + @ITerminalService private readonly terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): Promise { + const terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance && terminalInstance.navigationMode) { + terminalInstance.navigationMode.exitNavigationMode(); + } + return Promise.resolve(undefined); + } +} + + + +export class NavigationModeFocusPreviousTerminalAction extends Action { + + public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS; + public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusPrevious', "Focus Previous Line (Navigation Mode)"); + + constructor( + id: string, label: string, + @ITerminalService private readonly terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): Promise { + const terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance && terminalInstance.navigationMode) { + terminalInstance.navigationMode.focusPreviousLine(); + } + return Promise.resolve(undefined); + } +} + +export class NavigationModeFocusNextTerminalAction extends Action { + + public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT; + public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusNext', "Focus Next Line (Navigation Mode)"); + + constructor( + id: string, label: string, + @ITerminalService private readonly terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): Promise { + const terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance && terminalInstance.navigationMode) { + terminalInstance.navigationMode.focusNextLine(); + } + return Promise.resolve(undefined); + } +} + export class ClearTerminalAction extends Action { public static readonly ID = TERMINAL_COMMAND_ID.CLEAR; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index 899cbf7f524..0da7d6c690b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -8,12 +8,15 @@ import * as platform from 'vs/base/common/platform'; import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ITerminalConfiguration, ITerminalFont, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalConfiguration, ITerminalFont, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import Severity from 'vs/base/common/severity'; import { Terminal as XTermTerminal } from 'xterm'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; import { Emitter, Event } from 'vs/base/common/event'; +import { basename } from 'vs/base/common/path'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionType } from 'vs/platform/extensions/common/extensions'; const MINIMUM_FONT_SIZE = 6; const MAXIMUM_FONT_SIZE = 25; @@ -35,7 +38,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { public constructor( private readonly _linuxDistro: LinuxDistro, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IConfigurationService private readonly _workspaceConfigurationService: IConfigurationService, + @IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService, @INotificationService private readonly _notificationService: INotificationService, @IStorageService private readonly _storageService: IStorageService ) { @@ -174,9 +177,9 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { public checkWorkspaceShellPermissions(osOverride: platform.OperatingSystem = platform.OS): boolean { // Check whether there is a workspace setting const platformKey = osOverride === platform.OperatingSystem.Windows ? 'windows' : osOverride === platform.OperatingSystem.Macintosh ? 'osx' : 'linux'; - const shellConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shell.${platformKey}`); - const shellArgsConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shellArgs.${platformKey}`); - const envConfigValue = this._workspaceConfigurationService.inspect<{ [key: string]: string }>(`terminal.integrated.env.${platformKey}`); + const shellConfigValue = this._configurationService.inspect(`terminal.integrated.shell.${platformKey}`); + const shellArgsConfigValue = this._configurationService.inspect(`terminal.integrated.shellArgs.${platformKey}`); + const envConfigValue = this._configurationService.inspect<{ [key: string]: string }>(`terminal.integrated.env.${platformKey}`); // Check if workspace setting exists and whether it's whitelisted let isWorkspaceShellAllowed: boolean | undefined = false; @@ -244,4 +247,48 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { } return r; } + + private readonly NO_RECOMMENDATIONS_KEY = 'terminalConfigHelper/launchRecommendationsIgnore'; + private recommendationsShown = false; + + public async showRecommendations(shellLaunchConfig: IShellLaunchConfig): Promise { + if (this.recommendationsShown) { + return; + } + this.recommendationsShown = true; + + if (platform.isWindows && shellLaunchConfig.executable && basename(shellLaunchConfig.executable).toLowerCase() === 'wsl.exe') { + if (this._storageService.getBoolean(this.NO_RECOMMENDATIONS_KEY, StorageScope.WORKSPACE, false)) { + return; + } + + if (! await this.isExtensionInstalled('ms-vscode-remote.remote-wsl')) { + this._notificationService.prompt( + Severity.Info, + nls.localize( + 'useWslExtension.title', + "Check out the 'Visual Studio Code Remote - WSL' extension for a great development experience in WSL. Click [here]({0}) to learn more.", + 'https://go.microsoft.com/fwlink/?linkid=2097212' + ), + [ + { + label: nls.localize('doNotShowAgain', "Don't Show Again"), + run: () => { + this._storageService.store(this.NO_RECOMMENDATIONS_KEY, true, StorageScope.WORKSPACE); + } + } + ], + { + sticky: true + } + ); + } + } + } + + private isExtensionInstalled(id: string): Promise { + return this._extensionManagementService.getInstalled(ExtensionType.User).then(extensions => { + return extensions.some(e => e.identifier.id === id); + }); + } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index 75e51bcfa22..1ab97705568 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -19,7 +19,7 @@ export class TerminalFindWidget extends SimpleFindWidget { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @ITerminalService private readonly _terminalService: ITerminalService ) { - super(_contextViewService, _contextKeyService, findState, true); + super(_contextViewService, _contextKeyService, findState, true, true); this._register(findState.onFindReplaceStateChange(() => { this.show(); })); @@ -50,7 +50,7 @@ export class TerminalFindWidget extends SimpleFindWidget { // Ignore input changes for now const instance = this._terminalService.getActiveInstance(); if (instance !== null) { - return instance.findNext(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); + return instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); } return false; } @@ -78,4 +78,4 @@ export class TerminalFindWidget extends SimpleFindWidget { protected onFindInputFocusTrackerBlur() { this._findInputFocused.reset(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 76c6127aa99..31cdb6fb01b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; -import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; @@ -35,8 +35,9 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; -import { Terminal as XTermTerminal, IBuffer } from 'xterm'; +import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm'; import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; +import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -91,6 +92,9 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ TERMINAL_COMMAND_ID.SPLIT_IN_ACTIVE_WORKSPACE, TERMINAL_COMMAND_ID.SPLIT, TERMINAL_COMMAND_ID.TOGGLE, + TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT, + TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT, + TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS, 'editor.action.toggleTabFocusMode', 'workbench.action.quickOpen', 'workbench.action.quickOpenPreviousEditor', @@ -151,10 +155,21 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ let xtermConstructor: Promise | undefined; +interface ICanvasDimensions { + width: number; + height: number; +} + +interface IGridDimensions { + cols: number; + rows: number; +} + export class TerminalInstance implements ITerminalInstance { private static readonly EOL_REGEX = /\r?\n/g; - private static _lastKnownDimensions: dom.Dimension | null = null; + private static _lastKnownCanvasDimensions: ICanvasDimensions | undefined; + private static _lastKnownGridDimensions: IGridDimensions | undefined; private static _idCounter = 1; private _processManager: ITerminalProcessManager | undefined; @@ -172,6 +187,7 @@ export class TerminalInstance implements ITerminalInstance { private _xtermSearch: SearchAddon | undefined; private _xtermElement: HTMLDivElement; private _terminalHasTextContextKey: IContextKey; + private _terminalA11yTreeFocusContextKey: IContextKey; private _cols: number; private _rows: number; private _dimensionsOverride: ITerminalDimensions | undefined; @@ -180,12 +196,13 @@ export class TerminalInstance implements ITerminalInstance { private _titleReadyPromise: Promise; private _titleReadyComplete: (title: string) => any; - private _disposables: lifecycle.IDisposable[]; + private readonly _disposables = new lifecycle.DisposableStore(); private _messageTitleDisposable: lifecycle.IDisposable | undefined; private _widgetManager: TerminalWidgetManager; private _linkHandler: TerminalLinkHandler; private _commandTracker: TerminalCommandTracker; + private _navigationModeAddon: INavigationMode & ITerminalAddon | undefined; public disableLayout: boolean; public get id(): number { return this._id; } @@ -213,6 +230,7 @@ export class TerminalInstance implements ITerminalInstance { public get isTitleSetByProcess(): boolean { return !!this._messageTitleDisposable; } public get shellLaunchConfig(): IShellLaunchConfig { return this._shellLaunchConfig; } public get commandTracker(): TerminalCommandTracker { return this._commandTracker; } + public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; } private readonly _onExit = new Emitter(); public get onExit(): Event { return this._onExit.event; } @@ -257,7 +275,6 @@ export class TerminalInstance implements ITerminalInstance { @IStorageService private readonly _storageService: IStorageService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService ) { - this._disposables = []; this._skipTerminalCommands = []; this._isExiting = false; this._hadFocusOnExit = false; @@ -270,6 +287,7 @@ export class TerminalInstance implements ITerminalInstance { }); this._terminalHasTextContextKey = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.bindTo(this._contextKeyService); + this._terminalA11yTreeFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS.bindTo(this._contextKeyService); this.disableLayout = false; this._logService.trace(`terminalInstance#ctor (id: ${this.id})`, this._shellLaunchConfig); @@ -304,7 +322,7 @@ export class TerminalInstance implements ITerminalInstance { } public addDisposable(disposable: lifecycle.IDisposable): void { - this._disposables.push(disposable); + this._disposables.add(disposable); } private _initDimensions(): void { @@ -328,16 +346,19 @@ export class TerminalInstance implements ITerminalInstance { private _evaluateColsAndRows(width: number, height: number): number | null { // Ignore if dimensions are undefined or 0 if (!width || !height) { + this._setLastKnownColsAndRows(); return null; } const dimension = this._getDimension(width, height); if (!dimension) { + this._setLastKnownColsAndRows(); return null; } const font = this._configHelper.getFont(this._xterm); if (!font.charWidth || !font.charHeight) { + this._setLastKnownColsAndRows(); return null; } @@ -369,21 +390,28 @@ export class TerminalInstance implements ITerminalInstance { return dimension.width; } + private _setLastKnownColsAndRows(): void { + if (TerminalInstance._lastKnownGridDimensions) { + this._cols = TerminalInstance._lastKnownGridDimensions.cols; + this._rows = TerminalInstance._lastKnownGridDimensions.rows; + } + } + @debounce(50) private _fireMaximumDimensionsChanged(): void { this._onMaximumDimensionsChanged.fire(); } - private _getDimension(width: number, height: number): dom.Dimension | null { + private _getDimension(width: number, height: number): ICanvasDimensions | undefined { // The font needs to have been initialized const font = this._configHelper.getFont(this._xterm); if (!font || !font.charWidth || !font.charHeight) { - return null; + return undefined; } // The panel is minimized if (!this._isVisible) { - return TerminalInstance._lastKnownDimensions; + return TerminalInstance._lastKnownCanvasDimensions; } else { // Trigger scroll event manually so that the viewport's scroll area is synced. This // needs to happen otherwise its scrollTop value is invalid when the panel is toggled as @@ -395,7 +423,7 @@ export class TerminalInstance implements ITerminalInstance { } if (!this._wrapperElement) { - return null; + return undefined; } const wrapperElementStyle = getComputedStyle(this._wrapperElement); @@ -406,8 +434,8 @@ export class TerminalInstance implements ITerminalInstance { const innerWidth = width - marginLeft - marginRight; const innerHeight = height - bottom; - TerminalInstance._lastKnownDimensions = new dom.Dimension(innerWidth, innerHeight); - return TerminalInstance._lastKnownDimensions; + TerminalInstance._lastKnownCanvasDimensions = new dom.Dimension(innerWidth, innerHeight); + return TerminalInstance._lastKnownCanvasDimensions; } private async _getXtermConstructor(): Promise { @@ -442,13 +470,13 @@ export class TerminalInstance implements ITerminalInstance { letterSpacing: font.letterSpacing, lineHeight: font.lineHeight, bellStyle: config.enableBell ? 'sound' : 'none', - screenReaderMode: this._isScreenReaderOptimized(), macOptionIsMeta: config.macOptionIsMeta, macOptionClickForcesSelection: config.macOptionClickForcesSelection, rightClickSelectsWord: config.rightClickBehavior === 'selectWord', // TODO: Guess whether to use canvas or dom better rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType }); + this.updateAccessibilitySupport(); this._terminalInstanceService.getXtermSearchConstructor().then(Addon => { this._xtermSearch = new Addon(); this._xterm.loadAddon(this._xtermSearch); @@ -494,7 +522,7 @@ export class TerminalInstance implements ITerminalInstance { } this._commandTracker = new TerminalCommandTracker(this._xterm); - this._disposables.push(this._themeService.onThemeChange(theme => this._updateTheme(theme))); + this._disposables.add(this._themeService.onThemeChange(theme => this._updateTheme(theme))); } private _isScreenReaderOptimized(): boolean { @@ -576,7 +604,7 @@ export class TerminalInstance implements ITerminalInstance { return true; }); - this._disposables.push(dom.addDisposableListener(this._xterm.element, 'mousedown', () => { + this._disposables.add(dom.addDisposableListener(this._xterm.element, 'mousedown', () => { // We need to listen to the mouseup event on the document since the user may release // the mouse button anywhere outside of _xterm.element. const listener = dom.addDisposableListener(document, 'mouseup', () => { @@ -588,7 +616,7 @@ export class TerminalInstance implements ITerminalInstance { })); // xterm.js currently drops selection on keyup as we need to handle this case. - this._disposables.push(dom.addDisposableListener(this._xterm.element, 'keyup', () => { + this._disposables.add(dom.addDisposableListener(this._xterm.element, 'keyup', () => { // Wait until keyup has propagated through the DOM before evaluating // the new selection state. setTimeout(() => this._refreshSelectionContextKey(), 0); @@ -598,7 +626,7 @@ export class TerminalInstance implements ITerminalInstance { const focusTrap: HTMLElement = document.createElement('div'); focusTrap.setAttribute('tabindex', '0'); dom.addClass(focusTrap, 'focus-trap'); - this._disposables.push(dom.addDisposableListener(focusTrap, 'focus', () => { + this._disposables.add(dom.addDisposableListener(focusTrap, 'focus', () => { let currentElement = focusTrap; while (!dom.hasClass(currentElement, 'part')) { currentElement = currentElement.parentElement!; @@ -608,18 +636,18 @@ export class TerminalInstance implements ITerminalInstance { })); xtermHelper.insertBefore(focusTrap, this._xterm.textarea); - this._disposables.push(dom.addDisposableListener(this._xterm.textarea, 'focus', () => { + this._disposables.add(dom.addDisposableListener(this._xterm.textarea, 'focus', () => { this._terminalFocusContextKey.set(true); this._onFocused.fire(this); })); - this._disposables.push(dom.addDisposableListener(this._xterm.textarea, 'blur', () => { + this._disposables.add(dom.addDisposableListener(this._xterm.textarea, 'blur', () => { this._terminalFocusContextKey.reset(); this._refreshSelectionContextKey(); })); - this._disposables.push(dom.addDisposableListener(this._xterm.element, 'focus', () => { + this._disposables.add(dom.addDisposableListener(this._xterm.element, 'focus', () => { this._terminalFocusContextKey.set(true); })); - this._disposables.push(dom.addDisposableListener(this._xterm.element, 'blur', () => { + this._disposables.add(dom.addDisposableListener(this._xterm.element, 'blur', () => { this._terminalFocusContextKey.reset(); this._refreshSelectionContextKey(); })); @@ -713,9 +741,9 @@ export class TerminalInstance implements ITerminalInstance { return this._xterm && this._xterm.hasSelection(); } - public copySelection(): void { + public async copySelection(): Promise { if (this.hasSelection()) { - this._clipboardService.writeText(this._xterm.getSelection()); + await this._clipboardService.writeText(this._xterm.getSelection()); } else { this._notificationService.warn(nls.localize('terminal.integrated.copySelection.noSelection', 'The terminal has no selection to copy')); } @@ -798,7 +826,7 @@ export class TerminalInstance implements ITerminalInstance { this._isDisposed = true; this._onDisposed.fire(this); } - this._disposables = lifecycle.dispose(this._disposables); + this._disposables.dispose(); } public rendererExit(exitCode: number): void { @@ -841,9 +869,9 @@ export class TerminalInstance implements ITerminalInstance { return this._xtermReadyPromise.then(() => this.focus(force)); } - public paste(): void { + public async paste(): Promise { this.focus(); - document.execCommand('paste'); + this._xterm._core._coreService.triggerDataEvent(await this._clipboardService.readText(), true); } public write(text: string): void { @@ -938,7 +966,6 @@ export class TerminalInstance implements ITerminalInstance { private _refreshSelectionContextKey() { const activePanel = this._panelService.getActivePanel(); const isActive = !!activePanel && activePanel.getId() === TERMINAL_PANEL_ID; - this._terminalHasTextContextKey.set(isActive && this.hasSelection()); } @@ -948,6 +975,7 @@ export class TerminalInstance implements ITerminalInstance { this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode)); this._processManager.onProcessData(data => this._onData.fire(data)); this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e)); + this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e)); if (this._shellLaunchConfig.name) { this.setTitle(this._shellLaunchConfig.name, false); @@ -1203,7 +1231,17 @@ export class TerminalInstance implements ITerminalInstance { } public updateAccessibilitySupport(): void { - this._xterm.setOption('screenReaderMode', this._isScreenReaderOptimized()); + const isEnabled = this._isScreenReaderOptimized(); + if (isEnabled) { + this._navigationModeAddon = new NavigationModeAddon(this._terminalA11yTreeFocusContextKey); + this._xterm.loadAddon(this._navigationModeAddon); + } else { + if (this._navigationModeAddon) { + this._navigationModeAddon.dispose(); + this._navigationModeAddon = undefined; + } + } + this._xterm.setOption('screenReaderMode', isEnabled); } private _setCursorBlink(blink: boolean): void { @@ -1296,7 +1334,9 @@ export class TerminalInstance implements ITerminalInstance { if (cols !== this._xterm.cols || rows !== this._xterm.rows) { this._onDimensionsChanged.fire(); } + this._xterm.resize(cols, rows); + TerminalInstance._lastKnownGridDimensions = { cols, rows }; if (this._isVisible) { // HACK: Force the renderer to unpause by simulating an IntersectionObserver event. @@ -1357,6 +1397,13 @@ export class TerminalInstance implements ITerminalInstance { this._resize(); } + private _setResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { + this._shellLaunchConfig.args = shellLaunchConfig.args; + this._shellLaunchConfig.cwd = shellLaunchConfig.cwd; + this._shellLaunchConfig.executable = shellLaunchConfig.executable; + this._shellLaunchConfig.env = shellLaunchConfig.env; + } + private _getXtermTheme(theme?: ITheme): any { if (!theme) { theme = this._themeService.getTheme(); @@ -1398,8 +1445,7 @@ export class TerminalInstance implements ITerminalInstance { } public toggleEscapeSequenceLogging(): void { - this._xterm._core.debug = !this._xterm._core.debug; - this._xterm.setOption('debug', this._xterm._core.debug); + this._xterm.setOption('logLevel', 'debug'); } public getInitialCwd(): Promise { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 01d79e0c592..c79e4eedcb0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -203,7 +203,7 @@ export class TerminalPanel extends Panel { } private _attachEventListeners(): void { - this._register(dom.addDisposableListener(this._parentDomElement, 'mousedown', (event: MouseEvent) => { + this._register(dom.addDisposableListener(this._parentDomElement, 'mousedown', async (event: MouseEvent) => { if (this._terminalService.terminalInstances.length === 0) { return; } @@ -222,7 +222,7 @@ export class TerminalPanel extends Panel { return; } if (terminal.hasSelection()) { - terminal.copySelection(); + await terminal.copySelection(); terminal.clearSelection(); } else { terminal.paste(); @@ -240,7 +240,7 @@ export class TerminalPanel extends Panel { } } })); - this._register(dom.addDisposableListener(this._parentDomElement, 'mouseup', (event: MouseEvent) => { + this._register(dom.addDisposableListener(this._parentDomElement, 'mouseup', async (event: MouseEvent) => { if (this._configurationService.getValue('terminal.integrated.copyOnSelection')) { if (this._terminalService.terminalInstances.length === 0) { return; @@ -249,7 +249,7 @@ export class TerminalPanel extends Panel { if (event.which === 1) { const terminal = this._terminalService.getActiveInstance(); if (terminal && terminal.hasSelection()) { - terminal.copySelection(); + await terminal.copySelection(); } } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 5bbb0612709..348b93e3307 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -31,7 +31,7 @@ const LATENCY_MEASURING_INTERVAL = 1000; enum ProcessType { Process, - VirtualProcess + ExtensionTerminal } /** @@ -70,6 +70,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { public get onProcessExit(): Event { return this._onProcessExit.event; } private readonly _onProcessOverrideDimensions = new Emitter(); public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } + private readonly _onProcessOverrideShellLaunchConfig = new Emitter(); + public get onProcessResolvedShellLaunchConfig(): Event { return this._onProcessOverrideShellLaunchConfig.event; } constructor( private readonly _terminalId: number, @@ -111,8 +113,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { rows: number, isScreenReaderModeEnabled: boolean ): Promise { - if (shellLaunchConfig.isVirtualProcess) { - this._processType = ProcessType.VirtualProcess; + if (shellLaunchConfig.isExtensionTerminal) { + this._processType = ProcessType.ExtensionTerminal; this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, undefined, cols, rows, this._configHelper); } else { const forceExtHostProcess = (this._configHelper.config as any).extHostProcess; @@ -170,6 +172,9 @@ export class TerminalProcessManager implements ITerminalProcessManager { if (this._process.onProcessOverrideDimensions) { this._process.onProcessOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e)); } + if (this._process.onProcessResolvedShellLaunchConfig) { + this._process.onProcessResolvedShellLaunchConfig(e => this._onProcessOverrideShellLaunchConfig.fire(e)); + } setTimeout(() => { if (this.processState === ProcessState.LAUNCHING) { @@ -184,19 +189,32 @@ export class TerminalProcessManager implements ITerminalProcessManager { rows: number, isScreenReaderModeEnabled: boolean ): Promise { + const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); + const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux'); + const lastActiveWorkspace = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null; if (!shellLaunchConfig.executable) { const defaultConfig = await this._terminalInstanceService.getDefaultShellAndArgs(); shellLaunchConfig.executable = defaultConfig.shell; shellLaunchConfig.args = defaultConfig.args; + } else { + shellLaunchConfig.executable = this._configurationResolverService.resolve(lastActiveWorkspace === null ? undefined : lastActiveWorkspace, shellLaunchConfig.executable); + if (shellLaunchConfig.args) { + if (Array.isArray(shellLaunchConfig.args)) { + const resolvedArgs: string[] = []; + for (const arg of shellLaunchConfig.args) { + resolvedArgs.push(this._configurationResolverService.resolve(lastActiveWorkspace === null ? undefined : lastActiveWorkspace, arg)); + } + shellLaunchConfig.args = resolvedArgs; + } else { + shellLaunchConfig.args = this._configurationResolverService.resolve(lastActiveWorkspace === null ? undefined : lastActiveWorkspace, shellLaunchConfig.args); + } + } } - const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentService.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd); - - const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux'); - const lastActiveWorkspace = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null; const envFromConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.env.${platformKey}`); const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions(); + this._configHelper.showRecommendations(shellLaunchConfig); const baseEnv = this._configHelper.config.inheritEnv ? process.env as platform.IProcessEnvironment : await this._terminalInstanceService.getMainProcessParentEnv(); const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables, baseEnv); @@ -221,7 +239,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { } public write(data: string): void { - if (this.shellProcessId || this._processType === ProcessType.VirtualProcess) { + if (this.shellProcessId || this._processType === ProcessType.ExtensionTerminal) { if (this._process) { // Send data if the pty is ready this._process.input(data); @@ -274,4 +292,4 @@ export class TerminalProcessManager implements ITerminalProcessManager { this._onProcessExit.fire(exitCode); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 1b117021f53..9ca71e3d27b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -49,7 +49,7 @@ export class TerminalService extends CommonTerminalService implements ITerminalS this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this.terminalNativeService.linuxDistro); } - public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { + public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); this._onInstanceCreated.fire(instance); return instance; @@ -60,8 +60,7 @@ export class TerminalService extends CommonTerminalService implements ITerminalS const instance = this.createInstance(this._terminalFocusContextKey, this.configHelper, undefined, - shell, - true); + shell); this._backgroundedTerminalInstances.push(instance); this._initInstanceListeners(instance); return instance; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts index 42b1a59d7c2..e00296853ff 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ITerminalInstance, IShellLaunchConfig, ITerminalTab, Direction, ITerminalService, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { SplitView, Orientation, IView, Sizing } from 'vs/base/browser/ui/splitview/splitview'; import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -15,11 +15,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti const SPLIT_PANE_MIN_SIZE = 120; const TERMINAL_MIN_USEFUL_SIZE = 250; -class SplitPaneContainer { +class SplitPaneContainer extends Disposable { private _height: number; private _width: number; private _splitView: SplitView; - private _splitViewDisposables: IDisposable[]; + private readonly _splitViewDisposables = this._register(new DisposableStore()); private _children: SplitPane[] = []; private _onDidChange: Event = Event.None; @@ -30,6 +30,7 @@ class SplitPaneContainer { public orientation: Orientation, @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService ) { + super(); this._width = this._container.offsetWidth; this._height = this._container.offsetHeight; this._createSplitView(); @@ -38,8 +39,8 @@ class SplitPaneContainer { private _createSplitView(): void { this._splitView = new SplitView(this._container, { orientation: this.orientation }); - this._splitViewDisposables = []; - this._splitViewDisposables.push(this._splitView.onDidSashReset(() => this._splitView.distributeViewSizes())); + this._splitViewDisposables.clear(); + this._splitViewDisposables.add(this._splitView.onDidSashReset(() => this._splitView.distributeViewSizes())); } public split(instance: ITerminalInstance, index: number = this._children.length): void { @@ -149,8 +150,7 @@ class SplitPaneContainer { while (this._container.children.length > 0) { this._container.removeChild(this._container.children[0]); } - this._splitViewDisposables.forEach(d => d.dispose()); - this._splitViewDisposables = []; + this._splitViewDisposables.clear(); this._splitView.dispose(); // Create new split view with updated orientation @@ -222,10 +222,10 @@ export class TerminalTab extends Disposable implements ITerminalTab { public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; } - private readonly _onDisposed: Emitter; - public get onDisposed(): Event { return this._onDisposed.event; } - private readonly _onInstancesChanged: Emitter; - public get onInstancesChanged(): Event { return this._onInstancesChanged.event; } + private readonly _onDisposed: Emitter = new Emitter(); + public readonly onDisposed: Event = this._onDisposed.event; + private readonly _onInstancesChanged: Emitter = new Emitter(); + public readonly onInstancesChanged: Event = this._onInstancesChanged.event; constructor( terminalFocusContextKey: IContextKey, @@ -237,8 +237,6 @@ export class TerminalTab extends Disposable implements ITerminalTab { @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); - this._onDisposed = new Emitter(); - this._onInstancesChanged = new Emitter(); let instance: ITerminalInstance; if ('id' in shellLaunchConfigOrInstance) { @@ -248,8 +246,7 @@ export class TerminalTab extends Disposable implements ITerminalTab { terminalFocusContextKey, configHelper, undefined, - shellLaunchConfigOrInstance, - true); + shellLaunchConfigOrInstance); } this._terminalInstances.push(instance); this._initInstanceListeners(instance); @@ -391,8 +388,7 @@ export class TerminalTab extends Disposable implements ITerminalTab { terminalFocusContextKey, configHelper, undefined, - shellLaunchConfig, - true); + shellLaunchConfig); this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance); this._initInstanceListeners(instance); this._setActiveInstance(instance); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts index 9fb22f4deb3..8beb67cb689 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; const WIDGET_HEIGHT = 29; @@ -12,7 +12,7 @@ export class TerminalWidgetManager implements IDisposable { private _xtermViewport: HTMLElement | null; private _messageWidget: MessageWidget; - private _messageListeners: IDisposable[] = []; + private readonly _messageListeners = new DisposableStore(); constructor( terminalWrapper: HTMLElement @@ -30,6 +30,7 @@ export class TerminalWidgetManager implements IDisposable { this._container = null; } this._xtermViewport = null; + this._messageListeners.dispose(); } private _initTerminalHeightWatcher(terminalWrapper: HTMLElement) { @@ -47,14 +48,14 @@ export class TerminalWidgetManager implements IDisposable { return; } dispose(this._messageWidget); - this._messageListeners = dispose(this._messageListeners); + this._messageListeners.clear(); this._messageWidget = new MessageWidget(this._container, left, top, text); } public closeMessage(): void { - this._messageListeners = dispose(this._messageListeners); + this._messageListeners.clear(); if (this._messageWidget) { - this._messageListeners.push(MessageWidget.fadeOut(this._messageWidget)); + this._messageListeners.add(MessageWidget.fadeOut(this._messageWidget)); } } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 643d0aaeda2..f6413d9857e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -21,6 +21,8 @@ export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('t export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false); /** A context key that is set when the integrated terminal does not have focus. */ export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated(); +/** A context key that is set when the user is navigating the accessibility tree */ +export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey('terminalA11yTreeFocus', false); /** A keybinding context key that is set when the integrated terminal has text selected. */ export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false); @@ -122,6 +124,7 @@ export interface ITerminalConfigHelper { /** Sets whether a workspace shell configuration is allowed or not */ setWorkspaceShellAllowed(isAllowed: boolean): void; checkWorkspaceShellPermissions(osOverride?: OperatingSystem): boolean; + showRecommendations(shellLaunchConfig: IShellLaunchConfig): void; } export interface ITerminalFont { @@ -185,14 +188,14 @@ export interface IShellLaunchConfig { initialText?: string; /** - * @deprecated use `isVirtualProcess` + * @deprecated use `isExtensionTerminal` */ isRendererOnly?: boolean; /** - * When true an extension is acting as the terminal's process. + * Whether an extension is controlling the terminal via a `vscode.Pseudoterminal`. */ - isVirtualProcess?: boolean; + isExtensionTerminal?: boolean; /** * Whether the terminal process environment should be exactly as provided in @@ -228,8 +231,8 @@ export interface ITerminalService { onInstanceProcessIdReady: Event; onInstanceDimensionsChanged: Event; onInstanceMaximumDimensionsChanged: Event; - onInstanceRequestExtHostProcess: Event; - onInstanceRequestVirtualProcess: Event; + onInstanceRequestSpawnExtHostProcess: Event; + onInstanceRequestStartExtensionTerminal: Event; onInstancesChanged: Event; onInstanceTitleChanged: Event; onActiveInstanceChanged: Event; @@ -250,7 +253,7 @@ export interface ITerminalService { /** * Creates a raw terminal instance, this should not be used outside of the terminal part. */ - createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; + createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; getTabLabels(): string[]; @@ -296,8 +299,8 @@ export interface ITerminalService { preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; extHostReady(remoteAuthority: string): void; - requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - requestVirtualProcess(proxy: ITerminalProcessExtHostProxy): void; + requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; } /** @@ -482,6 +485,8 @@ export interface ITerminalInstance { */ readonly commandTracker: ITerminalCommandTracker; + readonly navigationMode: INavigationMode | undefined; + /** * Dispose the terminal instance, removing it from the panel/service and freeing up resources. * @@ -533,7 +538,7 @@ export interface ITerminalInstance { /** * Copies the terminal selection to the clipboard. */ - copySelection(): void; + copySelection(): Promise; /** * Current selection in the terminal. @@ -583,7 +588,7 @@ export interface ITerminalInstance { /** * Focuses and pastes the contents of the clipboard into the terminal instance. */ - paste(): void; + paste(): Promise; /** * Send text to the terminal instance. The text is written to the stdin of the underlying pty @@ -628,17 +633,6 @@ export interface ITerminalInstance { */ attachToElement(container: HTMLElement): void; - /** - * Updates the configuration of the terminal instance. - */ - updateConfig(): void; - - /** - * Updates the accessibility support state of the terminal instance. - * @param isEnabled Whether it's enabled. - */ - updateAccessibilitySupport(isEnabled: boolean): void; - /** * Configure the dimensions of the terminal instance. * @@ -686,6 +680,12 @@ export interface ITerminalCommandTracker { selectToNextLine(): void; } +export interface INavigationMode { + exitNavigationMode(): void; + focusPreviousLine(): void; + focusNextLine(): void; +} + export interface IBeforeProcessDataEvent { /** * The data of the event, this can be modified by the event listener to change what gets sent @@ -708,6 +708,7 @@ export interface ITerminalProcessManager extends IDisposable { readonly onProcessTitle: Event; readonly onProcessExit: Event; readonly onProcessOverrideDimensions: Event; + readonly onProcessResolvedShellLaunchConfig: Event; dispose(immediate?: boolean): void; createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number, isScreenReaderModeEnabled: boolean): Promise; @@ -746,6 +747,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { emitReady(pid: number, cwd: string): void; emitExit(exitCode: number): void; emitOverrideDimensions(dimensions: ITerminalDimensions | undefined): void; + emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void; emitInitialCwd(initialCwd: string): void; emitCwd(cwd: string): void; emitLatency(latency: number): void; @@ -758,7 +760,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { onRequestLatency: Event; } -export interface ITerminalProcessExtHostRequest { +export interface ISpawnExtHostProcessRequest { proxy: ITerminalProcessExtHostProxy; shellLaunchConfig: IShellLaunchConfig; activeWorkspaceRootUri: URI; @@ -767,6 +769,12 @@ export interface ITerminalProcessExtHostRequest { isWorkspaceShellAllowed: boolean; } +export interface IStartExtensionTerminalRequest { + proxy: ITerminalProcessExtHostProxy; + cols: number; + rows: number; +} + export interface IAvailableShellsRequest { (shells: IShellDefinition[]): void; } @@ -795,6 +803,7 @@ export interface ITerminalChildProcess { onProcessReady: Event<{ pid: number, cwd: string }>; onProcessTitleChanged: Event; onProcessOverrideDimensions?: Event; + onProcessResolvedShellLaunchConfig?: Event; /** * Shutdown the terminal process. diff --git a/src/vs/workbench/contrib/terminal/common/terminalCommands.ts b/src/vs/workbench/contrib/terminal/common/terminalCommands.ts index 8dd482ffbab..60da258805d 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalCommands.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalCommands.ts @@ -68,6 +68,9 @@ export const enum TERMINAL_COMMAND_ID { TOGGLE_FIND_REGEX_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindRegexTerminalFocus', TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindWholeWordTerminalFocus', TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindCaseSensitiveTerminalFocus', + NAVIGATION_MODE_EXIT = 'workbench.action.terminal.navigationModeExit', + NAVIGATION_MODE_FOCUS_NEXT = 'workbench.action.terminal.navigationModeFocusNext', + NAVIGATION_MODE_FOCUS_PREVIOUS = 'workbench.action.terminal.navigationModeFocusPrevious' } export function setupTerminalCommands(): void { diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index db22a46964d..da109a496f4 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -106,6 +106,7 @@ function _getLangEnvVariable(locale?: string) { ko: 'KR', pl: 'PL', ru: 'RU', + sk: 'SK', zh: 'CN' }; if (parts[0] in languageVariants) { @@ -169,7 +170,9 @@ export function getDefaultShell( defaultShell: string, isWoW64: boolean, windir: string | undefined, - platformOverride: platform.Platform = platform.platform + lastActiveWorkspace: IWorkspaceFolder | undefined, + configurationResolverService: IConfigurationResolverService | undefined, + platformOverride: platform.Platform = platform.platform, ): string { const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux'; const shellConfigValue = fetchSetting(`terminal.integrated.shell.${platformKey}`); @@ -190,17 +193,33 @@ export function getDefaultShell( executable = executable.replace(/\//g, '\\'); } + if (configurationResolverService) { + executable = configurationResolverService.resolve(lastActiveWorkspace, executable); + } + return executable; } export function getDefaultShellArgs( fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined }, isWorkspaceShellAllowed: boolean, - platformOverride: platform.Platform = platform.platform -): string[] { + lastActiveWorkspace: IWorkspaceFolder | undefined, + configurationResolverService: IConfigurationResolverService | undefined, + platformOverride: platform.Platform = platform.platform, +): string | string[] { const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux'; const shellArgsConfigValue = fetchSetting(`terminal.integrated.shellArgs.${platformKey}`); - const args = (isWorkspaceShellAllowed ? shellArgsConfigValue.value : shellArgsConfigValue.user) || shellArgsConfigValue.default; + let args = ((isWorkspaceShellAllowed ? shellArgsConfigValue.value : shellArgsConfigValue.user) || shellArgsConfigValue.default); + if (typeof args === 'string' && platformOverride === platform.Platform.Windows) { + return configurationResolverService ? configurationResolverService.resolve(lastActiveWorkspace, args) : args; + } + if (configurationResolverService) { + const resolvedArgs: string[] = []; + for (const arg of args) { + resolvedArgs.push(configurationResolverService.resolve(lastActiveWorkspace, arg)); + } + args = resolvedArgs; + } return args; } @@ -237,14 +256,14 @@ export function createTerminalEnvironment( } } - // Merge config (settings) and ShellLaunchConfig environments - mergeEnvironments(env, allowedEnvFromConfig); - mergeEnvironments(env, shellLaunchConfig.env); - // Sanitize the environment, removing any undesirable VS Code and Electron environment // variables sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI'); + // Merge config (settings) and ShellLaunchConfig environments + mergeEnvironments(env, allowedEnvFromConfig); + mergeEnvironments(env, shellLaunchConfig.env); + // Adding other env keys necessary to create the process addTerminalEnvironmentKeys(env, version, platform.locale, setLocaleVariables); } diff --git a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts index f551c553efb..80923d84486 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts @@ -24,6 +24,8 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; private readonly _onProcessOverrideDimensions = new Emitter(); public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } + private readonly _onProcessResolvedShellLaunchConfig = new Emitter(); + public get onProcessResolvedShellLaunchConfig(): Event { return this._onProcessResolvedShellLaunchConfig.event; } private readonly _onInput = this._register(new Emitter()); public readonly onInput: Event = this._onInput.event; @@ -56,14 +58,14 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal // Request a process if needed, if this is a virtual process this step can be skipped as // there is no real "process" and we know it's ready on the ext host already. - if (shellLaunchConfig.isVirtualProcess) { - this._terminalService.requestVirtualProcess(this); + if (shellLaunchConfig.isExtensionTerminal) { + this._terminalService.requestStartExtensionTerminal(this, cols, rows); } else { remoteAgentService.getEnvironment().then(env => { if (!env) { throw new Error('Could not fetch environment'); } - this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os)); + this._terminalService.requestSpawnExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os)); }); if (!hasReceivedResponse) { setTimeout(() => this._onProcessTitleChanged.fire(nls.localize('terminal.integrated.starting', "Starting...")), 0); @@ -93,6 +95,10 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal this._onProcessOverrideDimensions.fire(dimensions); } + public emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { + this._onProcessResolvedShellLaunchConfig.fire(shellLaunchConfig); + } + public emitInitialCwd(initialCwd: string): void { while (this._pendingInitialCwdRequests.length > 0) { this._pendingInitialCwdRequests.pop()!(initialCwd); @@ -143,4 +149,4 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal this._pendingLatencyRequests.push(resolve); }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 6aed26e5885..8bf6a5bfa5b 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; @@ -20,11 +20,15 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform'; import { basename } from 'vs/base/common/path'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { timeout } from 'vs/base/common/async'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; import { IPickOptions, IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +interface IExtHostReadyEntry { + promise: Promise; + resolve: () => void; +} + export abstract class TerminalService implements ITerminalService { public _serviceBrand: any; @@ -38,7 +42,7 @@ export abstract class TerminalService implements ITerminalService { return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); } private _findState: FindReplaceState; - private _extHostsReady: { [authority: string]: boolean } = {}; + private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {}; private _activeTabIndex: number; public get activeTabIndex(): number { return this._activeTabIndex; } @@ -53,10 +57,10 @@ export abstract class TerminalService implements ITerminalService { public get onInstanceDisposed(): Event { return this._onInstanceDisposed.event; } protected readonly _onInstanceProcessIdReady = new Emitter(); public get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.event; } - protected readonly _onInstanceRequestExtHostProcess = new Emitter(); - public get onInstanceRequestExtHostProcess(): Event { return this._onInstanceRequestExtHostProcess.event; } - protected readonly _onInstanceRequestVirtualProcess = new Emitter(); - public get onInstanceRequestVirtualProcess(): Event { return this._onInstanceRequestVirtualProcess.event; } + protected readonly _onInstanceRequestSpawnExtHostProcess = new Emitter(); + public get onInstanceRequestSpawnExtHostProcess(): Event { return this._onInstanceRequestSpawnExtHostProcess.event; } + protected readonly _onInstanceRequestStartExtensionTerminal = new Emitter(); + public get onInstanceRequestStartExtensionTerminal(): Event { return this._onInstanceRequestStartExtensionTerminal.event; } protected readonly _onInstanceDimensionsChanged = new Emitter(); public get onInstanceDimensionsChanged(): Event { return this._onInstanceDimensionsChanged.event; } protected readonly _onInstanceMaximumDimensionsChanged = new Emitter(); @@ -119,7 +123,7 @@ export abstract class TerminalService implements ITerminalService { protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; - public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; + public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; public createTerminalRenderer(name: string): ITerminalInstance { @@ -131,26 +135,39 @@ export abstract class TerminalService implements ITerminalService { return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); } - public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { + public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { this._extensionService.whenInstalledExtensionsRegistered().then(async () => { - // Wait for the remoteAuthority to be ready (and listening for events) before proceeding + // Wait for the remoteAuthority to be ready (and listening for events) before firing + // the event to spawn the ext host process const conn = this._remoteAgentService.getConnection(); const remoteAuthority = conn ? conn.remoteAuthority : 'null'; - let retries = 0; - while (!this._extHostsReady[remoteAuthority] && ++retries < 50) { - await timeout(100); - } - this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); + await this._whenExtHostReady(remoteAuthority); + this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); }); } - public requestVirtualProcess(proxy: ITerminalProcessExtHostProxy): void { - // Don't need to wait on extensions here as this can only be triggered by an extension - this._onInstanceRequestVirtualProcess.fire(proxy); + public requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { + this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows }); } - public extHostReady(remoteAuthority: string): void { - this._extHostsReady[remoteAuthority] = true; + public async extHostReady(remoteAuthority: string): Promise { + this._createExtHostReadyEntry(remoteAuthority); + this._extHostsReady[remoteAuthority]!.resolve(); + } + + private async _whenExtHostReady(remoteAuthority: string): Promise { + this._createExtHostReadyEntry(remoteAuthority); + return this._extHostsReady[remoteAuthority]!.promise; + } + + private _createExtHostReadyEntry(remoteAuthority: string): void { + if (this._extHostsReady[remoteAuthority]) { + return; + } + + let resolve!: () => void; + const promise = new Promise(r => resolve = r); + this._extHostsReady[remoteAuthority] = { promise, resolve }; } private _onBeforeShutdown(): boolean | Promise { diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index 94b5a713671..e9b13c0d68f 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -17,6 +17,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { getDefaultShell, getDefaultShellArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage'; import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; +import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; let Terminal: typeof XTermTerminal; let WebLinksAddon: typeof XTermWebLinksAddon; @@ -28,7 +31,10 @@ export class TerminalInstanceService implements ITerminalInstanceService { constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @IStorageService private readonly _storageService: IStorageService + @IStorageService private readonly _storageService: IStorageService, + @IConfigurationResolverService private readonly _configurationResolverService: IConfigurationResolverService, + @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, + @IHistoryService private readonly _historyService: IHistoryService ) { } @@ -65,19 +71,26 @@ export class TerminalInstanceService implements ITerminalInstanceService { return this._storageService.getBoolean(IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, StorageScope.WORKSPACE, false); } - public getDefaultShellAndArgs(platformOverride: Platform = platform): Promise<{ shell: string, args: string[] | undefined }> { + public getDefaultShellAndArgs(platformOverride: Platform = platform): Promise<{ shell: string, args: string | string[] }> { const isWorkspaceShellAllowed = this._isWorkspaceShellAllowed(); + const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(); + let lastActiveWorkspace = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : undefined; + lastActiveWorkspace = lastActiveWorkspace === null ? undefined : lastActiveWorkspace; const shell = getDefaultShell( (key) => this._configurationService.inspect(key), isWorkspaceShellAllowed, getSystemShell(platformOverride), process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'), process.env.windir, + lastActiveWorkspace, + this._configurationResolverService, platformOverride ); const args = getDefaultShellArgs( (key) => this._configurationService.inspect(key), isWorkspaceShellAllowed, + lastActiveWorkspace, + this._configurationResolverService, platformOverride ); return Promise.resolve({ shell, args }); diff --git a/src/vs/workbench/contrib/update/common/update.ts b/src/vs/workbench/contrib/update/common/update.ts new file mode 100644 index 00000000000..8fc0d5c041b --- /dev/null +++ b/src/vs/workbench/contrib/update/common/update.ts @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes'; \ No newline at end of file diff --git a/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts index 95c3f16b960..65d12c80877 100644 --- a/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/electron-browser/releaseNotesEditor.ts @@ -7,7 +7,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import * as marked from 'vs/base/common/marked/marked'; import { OS } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; -import { asText } from 'vs/base/node/request'; import { TokenizationRegistry, ITokenizationSupport } from 'vs/editor/common/modes'; import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; @@ -17,7 +16,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IRequestService } from 'vs/platform/request/node/request'; +import { IRequestService, asText } from 'vs/platform/request/common/request'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { addGAParameters } from 'vs/platform/telemetry/node/telemetryNodeUtils'; import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; @@ -27,6 +26,7 @@ import { KeybindingParser } from 'vs/base/common/keybindingParser'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { generateUuid } from 'vs/base/common/uuid'; function renderBody( body: string, @@ -48,10 +48,10 @@ 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; + private _lastText: string | undefined; public constructor( @IEnvironmentService private readonly _environmentService: IEnvironmentService, @@ -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,10 +88,11 @@ 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( + generateUuid(), 'releaseNotes', title, { group: ACTIVE_GROUP, preserveFocus: false }, @@ -102,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; @@ -161,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 @@ -171,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 9ab8d2d859a..ae89e3f4719 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'; @@ -29,6 +29,8 @@ import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/cont import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; +import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; +import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Uninitialized); @@ -97,7 +99,7 @@ export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesAction { - static readonly ID = 'update.showCurrentReleaseNotes'; + static readonly ID = ShowCurrentReleaseNotesActionId; static LABEL = nls.localize('showReleaseNotes', "Show Release Notes"); constructor( @@ -119,36 +121,44 @@ export class ProductContribution implements IWorkbenchContribution { @INotificationService notificationService: INotificationService, @IEnvironmentService environmentService: IEnvironmentService, @IOpenerService openerService: IOpenerService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IWindowService windowService: IWindowService, + @IWindowsService windowsService: IWindowsService ) { - const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); - const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); + windowsService.getActiveWindowId().then(async windowId => { + if (windowId !== windowService.windowId) { + return; + } - // was there an update? if so, open release notes - if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && product.releaseNotesUrl && lastVersion && pkg.version !== lastVersion) { - showReleaseNotes(instantiationService, pkg.version) - .then(undefined, () => { - notificationService.prompt( - severity.Info, - nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", product.nameLong, pkg.version), - [{ - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const uri = URI.parse(product.releaseNotesUrl); - openerService.open(uri); - } - }], - { sticky: true } - ); - }); - } + const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); + const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); - // should we show the new license? - if (product.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(pkg.version, '>=1.0.0')) { - notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", product.licenseUrl)); - } + // was there an update? if so, open release notes + if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && product.releaseNotesUrl && lastVersion && pkg.version !== lastVersion) { + showReleaseNotes(instantiationService, pkg.version) + .then(undefined, () => { + notificationService.prompt( + severity.Info, + nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", product.nameLong, pkg.version), + [{ + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const uri = URI.parse(product.releaseNotesUrl); + openerService.open(uri); + } + }], + { sticky: true } + ); + }); + } - storageService.store(ProductContribution.KEY, pkg.version, StorageScope.GLOBAL); + // should we show the new license? + if (product.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(pkg.version, '>=1.0.0')) { + notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", product.licenseUrl)); + } + + storageService.store(ProductContribution.KEY, pkg.version, StorageScope.GLOBAL); + }); } } diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index 7788f6e36a0..54c9b8620f5 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -173,7 +173,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr dom.prepend(container.firstElementChild as HTMLElement, this.watermark); this._register(this.keybindingService.onDidUpdateKeybindings(update)); this._register(this.editorGroupsService.onDidLayout(dimension => this.handleEditorPartSize(container, dimension))); - this.handleEditorPartSize(container, this.editorGroupsService.dimension); + this.handleEditorPartSize(container, this.editorGroupsService.contentDimension); } private handleEditorPartSize(container: HTMLElement, dimension: IDimension): void { @@ -214,4 +214,4 @@ Registry.as(ConfigurationExtensions.Configuration) 'description': nls.localize('tips.enabled', "When enabled, will show the watermark tips when no editor is open.") }, } - }); \ No newline at end of file + }); diff --git a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts new file mode 100644 index 00000000000..c86d25f7724 --- /dev/null +++ b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts @@ -0,0 +1,166 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. 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 { 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'; + +/** + * Webview editor overlay that creates and destroys the underlying webview as needed. + */ +export 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.onMessage(x => { this._onMessage.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); + + 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()); } + + public getInnerWebview() { + return this._webview.value; + } + + private withWebview(f: (webview: Webview) => void): void { + if (this._webview.value) { + f(this._webview.value); + } + } +} diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index af7c52ebdac..ac53ce590e2 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -4,7 +4,7 @@ + content="default-src 'none'; script-src 'self'; frame-src 'self'; style-src 'unsafe-inline'; worker-src 'self';" /> diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 1dc234fe681..63585fc25c2 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -367,7 +367,7 @@ // seeing the service worker applying properly. // Fake load an empty on the correct origin and then write real html // into it to get around this. - newFrame.src = `/fake.html?id=${ID}`; + newFrame.src = `./fake.html?id=${ID}`; } newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; document.body.appendChild(newFrame); diff --git a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js index 23f08be0281..8d26680d73a 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js +++ b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ const VERSION = 1; +const rootPath = self.location.pathname.replace(/\/service-worker.js$/, ''); + /** * Root path for resources */ -const resourceRoot = '/vscode-resource'; +const resourceRoot = rootPath + '/vscode-resource'; const resolveTimeout = 30000; @@ -179,7 +181,7 @@ async function processResourceRequest(event, requestUrl) { } const webviewId = getWebviewIdForClient(client); - const resourcePath = requestUrl.pathname.replace(resourceRoot, ''); + const resourcePath = requestUrl.pathname.startsWith(resourceRoot + '/') ? requestUrl.pathname.slice(resourceRoot.length) : requestUrl.pathname; function resolveResourceEntry(entry) { if (!entry) { @@ -269,6 +271,6 @@ async function getOuterIframeClient(webviewId) { const allClients = await self.clients.matchAll({ includeUncontrolled: true }); return allClients.find(client => { const clientUrl = new URL(client.url); - return clientUrl.pathname === '/' && clientUrl.search.match(new RegExp('\\bid=' + webviewId)); + return (clientUrl.pathname === `${rootPath}/` || clientUrl.pathname === `${rootPath}/index.html`) && clientUrl.search.match(new RegExp('\\bid=' + webviewId)); }); } \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts index 77a8253ff66..d01dc751d00 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 { - protected _webview: Webview | undefined; - protected findWidgetVisible: IContextKey; - public static readonly ID = 'WebviewEditor'; - private _editorFrame: HTMLElement; + private readonly _scopedContextKeyService = this._register(new MutableDisposable()); + private _findWidgetVisible: IContextKey; + + 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.findWidgetVisible.set(true); - } + 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._findWidgetVisible.reset(); + 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( - { - 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 2b114064420..c91e93d915f 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -3,124 +3,90 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { Emitter } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { memoize } from 'vs/base/common/decorators'; 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 { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; -import { WebviewEvents, WebviewInputOptions } from './webviewEditorService'; -import { Webview, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; +import { UnownedDisposable as Unowned } from 'vs/base/common/lifecycle'; -export class WebviewEditorInput extends EditorInput { - private static handlePool = 0; +class WebviewIconsManager { + private readonly _icons = new Map(); - private static _styleElement?: HTMLStyleElement; + @memoize + private get _styleElement(): HTMLStyleElement { + const element = dom.createStyleSheet(); + element.className = 'webview-icons'; + return element; + } - private static _icons = new Map(); - - private static updateStyleElement( - id: number, + public setIcons( + webviewId: string, iconPath: { light: URI, dark: URI } | undefined ) { - if (!this._styleElement) { - this._styleElement = dom.createStyleSheet(); - this._styleElement.className = 'webview-icons'; - } - - if (!iconPath) { - this._icons.delete(id); + if (iconPath) { + this._icons.set(webviewId, iconPath); } else { - this._icons.set(id, iconPath); + this._icons.delete(webviewId); } + this.updateStyleSheet(); + } + + private updateStyleSheet() { const cssRules: string[] = []; this._icons.forEach((value, key) => { const webviewSelector = `.show-file-icons .webview-${key}-name-file-icon::before`; if (URI.isUri(value)) { cssRules.push(`${webviewSelector} { content: ""; background-image: url(${dom.asDomUri(value).toString()}); }`); - } else { + } + else { cssRules.push(`.vs ${webviewSelector} { content: ""; background-image: url(${dom.asDomUri(value.light).toString()}); }`); cssRules.push(`.vs-dark ${webviewSelector} { content: ""; background-image: url(${dom.asDomUri(value.dark).toString()}); }`); } }); this._styleElement.innerHTML = cssRules.join('\n'); } +} + +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; - }; - private readonly _id: number; + private readonly _webview: WebviewEditorOverlay; 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, + webview: Unowned, ) { super(); - this._id = WebviewEditorInput.handlePool++; - this._name = name; - this._options = options; - this._events = events; - this._state = state; this.extension = extension; + + this._webview = this._register(webview.acquire()); // 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', - path: `webview-panel/webview-${this._id}` + path: `webview-panel/webview-${this.id}` }); } @@ -133,7 +99,7 @@ export class WebviewEditorInput extends EditorInput { } public getDescription() { - return null; + return undefined; } public setName(value: string): void { @@ -141,13 +107,17 @@ export class WebviewEditorInput extends EditorInput { this._onDidChangeLabel.fire(); } + public get webview() { + return this._webview; + } + public get iconPath() { return this._iconPath; } public set iconPath(value: { light: URI, dark: URI } | undefined) { this._iconPath = value; - WebviewEditorInput.updateStyleElement(this._id, value); + WebviewEditorInput.iconsManager.setIcons(this.id, value); } public matches(other: IEditorInput): boolean { @@ -158,162 +128,34 @@ 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; constructor( + 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: Unowned, ) { - super(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 66f9f0b8e25..b5f3ce40819 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts @@ -9,6 +9,7 @@ import { WebviewEditorInput } from './webviewEditorInput'; import { IWebviewEditorService, WebviewInputOptions } from './webviewEditorService'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { generateUuid } from 'vs/base/common/uuid'; interface SerializedIconPath { light: string | UriComponents; @@ -44,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 }; @@ -67,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(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; @@ -97,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 6064f07dd95..e81418df66a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts @@ -4,16 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { equals } from 'vs/base/common/arrays'; -import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, UnownedDisposable } 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'); @@ -26,6 +27,7 @@ export interface IWebviewEditorService { _serviceBrand: any; createWebview( + id: string, viewType: string, title: string, showOptions: ICreateWebViewShowOptions, @@ -34,10 +36,10 @@ export interface IWebviewEditorService { location: URI, id: ExtensionIdentifier }, - events: WebviewEvents ): WebviewEditorInput; reviveWebview( + id: string, viewType: string, title: string, iconPath: { light: URI, dark: URI } | undefined, @@ -75,21 +77,16 @@ 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()))) @@ -130,20 +127,24 @@ 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( + id: string, 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, viewType, title, options, {}, events, extension); + const webview = this.createWebiew(id, extension, options); + + const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, new UnownedDisposable(webview)); this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group); return webviewInput; } @@ -164,6 +165,7 @@ export class WebviewEditorService implements IWebviewEditorService { } public reviveWebview( + id: string, viewType: string, title: string, iconPath: { light: URI, dark: URI } | undefined, @@ -171,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, 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); @@ -186,8 +191,10 @@ export class WebviewEditorService implements IWebviewEditorService { const promise = new Promise(r => { resolve = r; }); this._revivalPool.add(webview, resolve!); return promise; - }); + }, new UnownedDisposable(webview)); + webviewInput.iconPath = iconPath; + if (typeof group === 'number') { webviewInput.updateGroup(group); } @@ -209,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; } @@ -233,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 ed7e22ab84d..aa4473313d4 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -32,11 +32,10 @@ export class IFrameWebview extends Disposable implements Webview { private content: WebviewContent; private _focused = false; - private readonly id: string; - private readonly _portMappingManager: WebviewPortMappingManager; constructor( + private readonly id: string, private _options: WebviewOptions, contentOptions: WebviewContentOptions, @IThemeService themeService: IThemeService, @@ -46,13 +45,15 @@ export class IFrameWebview extends Disposable implements Webview { @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); - if (typeof environmentService.webviewEndpoint !== 'string') { + const useExternalEndpoint = this._configurationService.getValue('webview.experimental.useExternalEndpoint'); + + if (typeof environmentService.webviewEndpoint !== 'string' && !useExternalEndpoint) { throw new Error('To use iframe based webviews, you must configure `environmentService.webviewEndpoint`'); } this._portMappingManager = this._register(new WebviewPortMappingManager( this._options.extension ? this._options.extension.location : undefined, - () => this.content.options.portMappings || [], + () => this.content.options.portMapping || [], tunnelService )); @@ -62,11 +63,9 @@ export class IFrameWebview extends Disposable implements Webview { state: undefined }; - this.id = `webview-${Date.now()}`; - this.element = document.createElement('iframe'); this.element.sandbox.add('allow-scripts', 'allow-same-origin'); - this.element.setAttribute('src', `${environmentService.webviewEndpoint}?id=${this.id}`); + this.element.setAttribute('src', `${this.endpoint}/index.html?id=${this.id}`); this.element.style.border = 'none'; this.element.style.width = '100%'; this.element.style.height = '100%'; @@ -144,13 +143,23 @@ export class IFrameWebview extends Disposable implements Webview { this._register(themeService.onThemeChange(this.style, this)); } + private get endpoint(): string { + const useExternalEndpoint = this._configurationService.getValue('webview.experimental.useExternalEndpoint'); + const baseEndpoint = useExternalEndpoint ? 'https://{{uuid}}.vscode-webview-test.com/8fa811108f0f0524c473020ef57b6620f6c201e1' : this.environmentService.webviewEndpoint!; + const endpoint = baseEndpoint.replace('{{uuid}}', this.id); + if (endpoint[endpoint.length - 1] === '/') { + return endpoint.slice(0, endpoint.length - 1); + } + return endpoint; + } + public mountTo(parent: HTMLElement) { if (this.element) { parent.appendChild(this.element); } } - public set options(options: WebviewContentOptions) { + public set contentOptions(options: WebviewContentOptions) { if (areWebviewInputOptionsEqual(options, this.content.options)) { return; } @@ -174,7 +183,7 @@ export class IFrameWebview extends Disposable implements Webview { private preprocessHtml(value: string): string { return value.replace(/(["'])vscode-resource:([^\s'"]+?)(["'])/gi, (_, startQuote, path, endQuote) => - `${startQuote}${this.environmentService.webviewEndpoint}/vscode-resource${path}${endQuote}`); + `${startQuote}${this.endpoint}/vscode-resource${path}${endQuote}`); } public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index 58448a143cb..1995a857f5e 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -4,8 +4,9 @@ *--------------------------------------------------------------------------------------------*/ 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, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; export class WebviewService implements IWebviewService { _serviceBrand: any; @@ -15,11 +16,18 @@ export class WebviewService implements IWebviewService { ) { } createWebview( + id: string, options: WebviewOptions, contentOptions: WebviewContentOptions - ): Webview { - return this._instantiationService.createInstance(WebviewElement, - options, - contentOptions); + ): WebviewElement { + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); } -} \ No newline at end of file + + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay { + return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions); + } +} diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index bf459a3c694..d6a73ff5d61 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. @@ -26,9 +26,16 @@ export interface IWebviewService { _serviceBrand: any; createWebview( + id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, - ): Webview; + ): WebviewElement; + + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay; } export const WebviewResourceScheme = 'vscode-resource'; @@ -40,19 +47,22 @@ export interface WebviewOptions { readonly id?: ExtensionIdentifier; }; readonly enableFindWidget?: boolean; + readonly tryRestoreScrollPosition?: boolean; + readonly retainContextWhenHidden?: boolean; } export interface WebviewContentOptions { readonly allowScripts?: boolean; readonly svgWhiteList?: string[]; readonly localResourceRoots?: ReadonlyArray; - readonly portMappings?: ReadonlyArray; + readonly portMapping?: ReadonlyArray; + readonly enableCommandUris?: boolean; } export interface Webview extends IDisposable { html: string; - options: WebviewContentOptions; + contentOptions: WebviewContentOptions; initialScrollProgress: number; state: string | undefined; @@ -64,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; @@ -78,4 +87,18 @@ 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; + + getInnerWebview(): Webview | undefined; +} + export const webviewDeveloperCategory = nls.localize('developer', "Developer"); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts index 13b7185842a..084163f0459 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts @@ -15,9 +15,9 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; import { IWebviewService, webviewDeveloperCategory } from 'vs/workbench/contrib/webview/common/webview'; import * as webviewCommands from 'vs/workbench/contrib/webview/electron-browser/webviewCommands'; -import { WebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService'; +import { ElectronWebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService'; -registerSingleton(IWebviewService, WebviewService, true); +registerSingleton(IWebviewService, ElectronWebviewService, true); const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts index 15f320ce9f1..a1d8ecda01a 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts @@ -8,7 +8,8 @@ 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'; +import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; export class OpenWebviewDeveloperToolsAction extends Action { static readonly ID = 'workbench.action.webview.openDeveloperTools'; @@ -86,12 +87,17 @@ 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); + } else if ((webview as WebviewEditorOverlay).getInnerWebview) { + const innerWebview = (webview as WebviewEditorOverlay).getInnerWebview(); + if (innerWebview instanceof ElectronWebviewBasedWebview) { + f(innerWebview); + } } }); } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 32d4b8d25f0..3c030feb235 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; @@ -296,7 +274,7 @@ export class WebviewElement extends Disposable implements Webview { private _focused = false; private readonly _onDidFocus = this._register(new Emitter()); - public get onDidFocus(): Event { return this._onDidFocus.event; } + public readonly onDidFocus: Event = this._onDidFocus.event; constructor( private readonly _options: WebviewOptions, @@ -349,7 +327,7 @@ export class WebviewElement extends Disposable implements Webview { this._register(new WebviewPortMappingProvider( session, _options.extension ? _options.extension.location : undefined, - () => (this.content.options.portMappings || []), + () => (this.content.options.portMapping || []), tunnelService, )); @@ -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 e8ccaee1881..ae8eb72d06f 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts @@ -3,23 +3,39 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; 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 { DynamicWebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay'; +import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, 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 ElectronWebviewService implements IWebviewService { _serviceBrand: any; constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IConfigurationService private readonly _configService: IConfigurationService, ) { } createWebview( + id: string, options: WebviewOptions, contentOptions: WebviewContentOptions - ): Webview { - return this._instantiationService.createInstance(WebviewElement, - options, - contentOptions); + ): WebviewElement { + const useExternalEndpoint = this._configService.getValue('webview.experimental.useExternalEndpoint'); + if (useExternalEndpoint) { + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); + } else { + return this._instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions); + } + } + + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay { + return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, 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 99693277ff1..f137c1a6fce 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { IExperimentService, ExperimentState } from 'vs/workbench/contrib/experiments/electron-browser/experimentService'; +import { IExperimentService, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { language, locale } from 'vs/base/common/platform'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -109,12 +109,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 64a9afe8fe8..ab0d4193c40 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -22,7 +22,8 @@ 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'; +import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { used } from 'vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page'; import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -457,7 +458,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); }); }); @@ -472,12 +473,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 7bae52d70b7..afd74dc859b 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -301,12 +301,6 @@ export class WalkThroughPart extends BaseEditor { const div = innerContent.querySelector(`#${id.replace(/\./g, '\\.')}`) as HTMLElement; const options = this.getEditorOptions(snippet.textEditorModel.getModeId()); - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : { - "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ const telemetryData = { target: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, snippet: i @@ -356,43 +350,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/main.ts b/src/vs/workbench/electron-browser/main.ts index f8aaa15b064..61c920df264 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -39,9 +39,9 @@ import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-brow import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/electron-browser/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationExportHelper'; diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d3c48734060..e10a49baee6 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/accessibility/node/accessibilityService.ts b/src/vs/workbench/services/accessibility/node/accessibilityService.ts index d9ace4fc45b..02b215b5a09 100644 --- a/src/vs/workbench/services/accessibility/node/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/node/accessibilityService.ts @@ -5,19 +5,23 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { isWindows } from 'vs/base/common/platform'; -import { Emitter, Event } from 'vs/base/common/event'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService'; -export class AccessibilityService implements IAccessibilityService { +export class AccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { _serviceBrand: any; private _accessibilitySupport = AccessibilitySupport.Unknown; - private readonly _onDidChangeAccessibilitySupport = new Emitter(); - readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; constructor( - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { } + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IContextKeyService readonly contextKeyService: IContextKeyService, + @IConfigurationService readonly configurationService: IConfigurationService + ) { + super(contextKeyService, configurationService); + } alwaysUnderlineAccessKeys(): Promise { if (!isWindows) { diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts index 0bdbc59813e..990d688b3cc 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -17,9 +17,9 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { DefaultEndOfLine } from 'vs/editor/common/model'; import { Schemas } from 'vs/base/common/network'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; diff --git a/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts index ffb7d1ebd83..f1826cd036a 100644 --- a/src/vs/workbench/services/commands/common/commandService.ts +++ b/src/vs/workbench/services/commands/common/commandService.ts @@ -22,6 +22,9 @@ export class CommandService extends Disposable implements ICommandService { private readonly _onWillExecuteCommand: Emitter = this._register(new Emitter()); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + private readonly _onDidExecuteCommand: Emitter = new Emitter(); + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; + constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @IExtensionService private readonly _extensionService: IExtensionService, @@ -77,8 +80,9 @@ export class CommandService extends Disposable implements ICommandService { return Promise.reject(new Error(`command '${id}' not found`)); } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]); + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 515c6df2fe3..fe76b1061e3 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -12,7 +12,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels'; import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES, ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -24,6 +24,20 @@ import { IConfigurationModel } from 'vs/platform/configuration/common/configurat import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { hash } from 'vs/base/common/hash'; +function whenProviderRegistered(scheme: string, fileService: IFileService): Promise { + if (fileService.canHandleResource(URI.from({ scheme }))) { + return Promise.resolve(); + } + return new Promise((c, e) => { + const disposable = fileService.onDidChangeFileSystemProviderRegistrations(e => { + if (e.scheme === scheme && e.added) { + disposable.dispose(); + c(); + } + }); + }); +} + export class UserConfiguration extends Disposable { private readonly parser: ConfigurationModelParser; @@ -66,7 +80,7 @@ export class UserConfiguration extends Disposable { export class RemoteUserConfiguration extends Disposable { private readonly _cachedConfiguration: CachedRemoteUserConfiguration; - private readonly _configurationFileService: ConfigurationFileService; + private readonly _fileService: IFileService; private _userConfiguration: FileServiceBasedRemoteUserConfiguration | CachedRemoteUserConfiguration; private _userConfigurationInitializationPromise: Promise | null = null; @@ -76,15 +90,15 @@ export class RemoteUserConfiguration extends Disposable { constructor( remoteAuthority: string, configurationCache: IConfigurationCache, - configurationFileService: ConfigurationFileService, + fileService: IFileService, remoteAgentService: IRemoteAgentService ) { super(); - this._configurationFileService = configurationFileService; + this._fileService = fileService; this._userConfiguration = this._cachedConfiguration = new CachedRemoteUserConfiguration(remoteAuthority, configurationCache); remoteAgentService.getEnvironment().then(async environment => { if (environment) { - const userConfiguration = this._register(new FileServiceBasedRemoteUserConfiguration(environment.settingsPath, REMOTE_MACHINE_SCOPES, this._configurationFileService)); + const userConfiguration = this._register(new FileServiceBasedRemoteUserConfiguration(environment.settingsPath, REMOTE_MACHINE_SCOPES, this._fileService)); this._register(userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel))); this._userConfigurationInitializationPromise = userConfiguration.initialize(); const configurationModel = await this._userConfigurationInitializationPromise; @@ -142,12 +156,12 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { constructor( private readonly configurationResource: URI, private readonly scopes: ConfigurationScope[] | undefined, - private readonly configurationFileService: ConfigurationFileService + private readonly fileService: IFileService ) { super(); this.parser = new ConfigurationModelParser(this.configurationResource.toString(), this.scopes); - this._register(configurationFileService.onFileChanges(e => this.handleFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleFileEvents(e))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50)); this._register(toDisposable(() => { this.stopWatchingResource(); @@ -156,7 +170,7 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { } private watchResource(): void { - this.fileWatcherDisposable = this.configurationFileService.watch(this.configurationResource); + this.fileWatcherDisposable = this.fileService.watch(this.configurationResource); } private stopWatchingResource(): void { @@ -166,7 +180,7 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { private watchDirectory(): void { const directory = resources.dirname(this.configurationResource); - this.directoryWatcherDisposable = this.configurationFileService.watch(directory); + this.directoryWatcherDisposable = this.fileService.watch(directory); } private stopWatchingDirectory(): void { @@ -175,15 +189,15 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { } async initialize(): Promise { - const exists = await this.configurationFileService.exists(this.configurationResource); + const exists = await this.fileService.exists(this.configurationResource); this.onResourceExists(exists); return this.reload(); } async reload(): Promise { try { - const content = await this.configurationFileService.readFile(this.configurationResource); - this.parser.parseContent(content); + const content = await this.fileService.readFile(this.configurationResource); + this.parser.parseContent(content.value.toString()); return this.parser.configurationModel; } catch (e) { return new ConfigurationModel(); @@ -279,7 +293,7 @@ class CachedRemoteUserConfiguration extends Disposable { export class WorkspaceConfiguration extends Disposable { - private readonly _configurationFileService: ConfigurationFileService; + private readonly _fileService: IFileService; private readonly _cachedConfiguration: CachedWorkspaceConfiguration; private _workspaceConfiguration: IWorkspaceConfiguration; private _workspaceConfigurationChangeDisposable: IDisposable = Disposable.None; @@ -293,10 +307,10 @@ export class WorkspaceConfiguration extends Disposable { constructor( configurationCache: IConfigurationCache, - configurationFileService: ConfigurationFileService + fileService: IFileService ) { super(); - this._configurationFileService = configurationFileService; + this._fileService = fileService; this._workspaceConfiguration = this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache); } @@ -304,7 +318,7 @@ export class WorkspaceConfiguration extends Disposable { this._workspaceIdentifier = workspaceIdentifier; if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { if (this._workspaceIdentifier.configPath.scheme === Schemas.file) { - this.switch(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); + this.switch(new FileServiceBasedWorkspaceConfiguration(this._fileService)); } else { this.waitAndSwitch(this._workspaceIdentifier); } @@ -339,9 +353,9 @@ export class WorkspaceConfiguration extends Disposable { } private async waitAndSwitch(workspaceIdentifier: IWorkspaceIdentifier): Promise { - await this._configurationFileService.whenProviderRegistered(workspaceIdentifier.configPath.scheme); + await whenProviderRegistered(workspaceIdentifier.configPath.scheme, this._fileService); if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { - const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); + const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._fileService)); await fileServiceBasedWorkspaceConfiguration.load(workspaceIdentifier); this.switch(fileServiceBasedWorkspaceConfiguration); this._loaded = true; @@ -396,13 +410,13 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork protected readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(private configurationFileService: ConfigurationFileService) { + constructor(private fileService: IFileService) { super(); this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(''); this.workspaceSettings = new ConfigurationModel(); - this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50)); this.workspaceConfigWatcher = this._register(this.watchWorkspaceConfigurationFile()); } @@ -420,9 +434,10 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork } let contents = ''; try { - contents = await this.configurationFileService.readFile(this._workspaceIdentifier.configPath); + const content = await this.fileService.readFile(this._workspaceIdentifier.configPath); + contents = content.value.toString(); } catch (error) { - const exists = await this.configurationFileService.exists(this._workspaceIdentifier.configPath); + const exists = await this.fileService.exists(this._workspaceIdentifier.configPath); if (exists) { errors.onUnexpectedError(error); } @@ -454,7 +469,7 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork } private watchWorkspaceConfigurationFile(): IDisposable { - return this._workspaceIdentifier ? this.configurationFileService.watch(this._workspaceIdentifier.configPath) : Disposable.None; + return this._workspaceIdentifier ? this.fileService.watch(this._workspaceIdentifier.configPath) : Disposable.None; } private handleWorkspaceFileEvents(event: FileChangesEvent): void { @@ -557,7 +572,7 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC protected readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private configurationFileService: ConfigurationFileService) { + constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private fileService: IFileService) { super(); this.configurationNames = [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY]; @@ -567,15 +582,16 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC this._cache = new ConfigurationModel(); this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50)); - this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); } async loadConfiguration(): Promise { const configurationContents = await Promise.all(this.configurationResources.map(async resource => { try { - return await this.configurationFileService.readFile(resource); + const content = await this.fileService.readFile(resource); + return content.value.toString(); } catch (error) { - const exists = await this.configurationFileService.exists(resource); + const exists = await this.fileService.exists(resource); if (exists) { errors.onUnexpectedError(error); } @@ -724,7 +740,7 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat readonly workspaceFolder: IWorkspaceFolder, configFolderRelativePath: string, private readonly workbenchState: WorkbenchState, - configurationFileService: ConfigurationFileService, + fileService: IFileService, configurationCache: IConfigurationCache ) { super(); @@ -732,13 +748,13 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat this.configurationFolder = resources.joinPath(workspaceFolder.uri, configFolderRelativePath); this.folderConfiguration = this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, configurationCache); if (workspaceFolder.uri.scheme === Schemas.file) { - this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService); + this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService); } else { - configurationFileService.whenProviderRegistered(workspaceFolder.uri.scheme) + whenProviderRegistered(workspaceFolder.uri.scheme, fileService) .then(() => { this.folderConfiguration.dispose(); this.folderConfigurationDisposable.dispose(); - this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService); + this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService); this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange())); this.onDidFolderConfigurationChange(); }); diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index b2b2f3469f9..50ffb6be24c 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -11,11 +11,10 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { Queue, Barrier } from 'vs/base/common/async'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { isLinux } from 'vs/base/common/platform'; import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; @@ -24,7 +23,6 @@ import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/wor import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; -import { localize } from 'vs/nls'; import { isEqual, dirname } from 'vs/base/common/resources'; import { mark } from 'vs/base/common/performance'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -47,7 +45,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private cachedFolderConfigs: ResourceMap; private workspaceEditingQueue: Queue; - private readonly configurationFileService: ConfigurationFileService; + private readonly fileService: IFileService; protected readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; @@ -78,16 +76,16 @@ export class WorkspaceService extends Disposable implements IConfigurationServic this.completeWorkspaceBarrier = new Barrier(); this.defaultConfiguration = new DefaultConfigurationModel(); this.configurationCache = configurationCache; - this.configurationFileService = new ConfigurationFileService(fileService); + this.fileService = fileService; this._configuration = new Configuration(this.defaultConfiguration, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap(), this.workspace); this.cachedFolderConfigs = new ResourceMap(); this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService)); this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); if (remoteAuthority) { - this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, this.configurationFileService, remoteAgentService)); + this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, fileService, remoteAgentService)); this._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration))); } - this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, this.configurationFileService)); + this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, fileService)); this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => { this.onWorkspaceConfigurationChanged(); if (this.workspaceConfiguration.loaded) { @@ -231,13 +229,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private contains(resources: URI[], toCheck: URI): boolean { - return resources.some(resource => { - if (isLinux) { - return resource.toString() === toCheck.toString(); - } - - return resource.toString().toLowerCase() === toCheck.toString().toLowerCase(); - }); + return resources.some(resource => isEqual(resource, toCheck)); } // Workspace Configuration Service Impl @@ -514,29 +506,29 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private registerConfigurationSchemas(): void { if (this.workspace) { const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); - const convertToNotSuggestedProperties = (properties: IJSONSchemaMap, errorMessage: string): IJSONSchemaMap => { + const convertToNotSuggestedProperties = (properties: IJSONSchemaMap): IJSONSchemaMap => { return Object.keys(properties).reduce((result: IJSONSchemaMap, property) => { result[property] = deepClone(properties[property]); - result[property].deprecationMessage = errorMessage; + result[property].doNotSuggest = true; return result; }, {}); }; - const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings")); - const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedMachineSetting', "This setting can be applied only in user settings")); - const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings")); - const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; - const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' } : allSettingsSchema; - const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; - const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties); + const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties); + const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties); + const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: true }; + const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true } : allSettingsSchema; + const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; + const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema); jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema); jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema); if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) { - const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties, localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.")); - const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties); + const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema); jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema); } else { @@ -618,7 +610,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic return Promise.all([...folders.map(folder => { let folderConfiguration = this.cachedFolderConfigs.get(folder.uri); if (!folderConfiguration) { - folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.configurationFileService, this.configurationCache); + folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.fileService, this.configurationCache); this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder))); this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); } diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index ca5948d81a6..170e3f136aa 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,9 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; export const FOLDER_CONFIG_FOLDER_NAME = '.vscode'; @@ -39,38 +36,4 @@ export interface IConfigurationCache { write(key: ConfigurationKey, content: string): Promise; remove(key: ConfigurationKey): Promise; -} - -export class ConfigurationFileService { - - constructor(private readonly fileService: IFileService) { } - - get onFileChanges() { return this.fileService.onFileChanges; } - - whenProviderRegistered(scheme: string): Promise { - if (this.fileService.canHandleResource(URI.from({ scheme }))) { - return Promise.resolve(); - } - return new Promise((c, e) => { - const disposable = this.fileService.onDidChangeFileSystemProviderRegistrations(e => { - if (e.scheme === scheme && e.added) { - disposable.dispose(); - c(); - } - }); - }); - } - - watch(resource: URI): IDisposable { - return this.fileService.watch(resource); - } - - exists(resource: URI): Promise { - return this.fileService.exists(resource); - } - - readFile(resource: URI): Promise { - return this.fileService.readFile(resource).then(content => content.value.toString()); - } - -} +} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 1b604be8ba7..2a75dca343d 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -32,10 +32,10 @@ import { URI } from 'vs/base/common/uri'; import { createHash } from 'crypto'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; import { KeybindingsEditingService, IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index 391474a310f..5f4a9ced4a2 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -36,13 +36,12 @@ import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration'; -// import { VSBuffer } from 'vs/base/common/buffer'; import { SignService } from 'vs/platform/sign/browser/signService'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; @@ -1603,7 +1602,7 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { // } // }); // }); - // await instantiationService.get(IFileService).writeFile(URI.file(remoteSettingsFile), VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }')); + // fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); // return promise; // }); diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index bcf4b31cef9..f406a3e0d63 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -227,6 +227,10 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR */ private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise { + if (!inputInfos) { + return Promise.reject(new Error(nls.localize('inputVariable.noInputSection', "Variable '{0}' must be defined in an '{1}' section of the debug or task configuration.", variable, 'input'))); + } + // find info for the given input variable const info = inputInfos.filter(item => item.id === variable).pop(); if (info) { @@ -307,4 +311,4 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi } } -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); \ No newline at end of file +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 43d8013dc31..a07fb3a264d 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -237,6 +237,13 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe } return getFilePath(); + case 'relativeFileDirname': + let dirname = paths.dirname(getFilePath()); + if (folderUri) { + return paths.normalize(paths.relative(getFolderUri().fsPath, dirname)); + } + return dirname; + case 'fileDirname': return paths.dirname(getFilePath()); diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index cefee9701c9..5b9f44514e9 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -523,6 +523,7 @@ class MockCommandService implements ICommandService { public callCount = 0; onWillExecuteCommand = () => Disposable.None; + onDidExecuteCommand = () => Disposable.None; public executeCommand(commandId: string, ...args: any[]): Promise { this.callCount++; diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index f0a715d5868..37d10c4d8fd 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -66,7 +66,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService _serviceBrand: any; private _onDidContextMenu = this._register(new Emitter()); - get onDidContextMenu(): Event { return this._onDidContextMenu.event; } + readonly onDidContextMenu: Event = this._onDidContextMenu.event; constructor( @INotificationService private readonly notificationService: INotificationService, diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 1a4e587636a..b183a2629d8 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; @@ -334,14 +334,15 @@ class DecorationProviderWrapper { } } -export class FileDecorationsService extends Disposable implements IDecorationsService { +export class FileDecorationsService implements IDecorationsService { _serviceBrand: any; private readonly _data = new LinkedList(); - private readonly _onDidChangeDecorationsDelayed = this._register(new Emitter()); - private readonly _onDidChangeDecorations = this._register(new Emitter()); + private readonly _onDidChangeDecorationsDelayed = new Emitter(); + private readonly _onDidChangeDecorations = new Emitter(); private readonly _decorationStyles: DecorationStyles; + private readonly _disposables: IDisposable[]; readonly onDidChangeDecorations: Event = Event.any( this._onDidChangeDecorations.event, @@ -355,17 +356,27 @@ export class FileDecorationsService extends Disposable implements IDecorationsSe constructor( @IThemeService themeService: IThemeService ) { - super(); - this._decorationStyles = this._register(new DecorationStyles(themeService)); + this._decorationStyles = new DecorationStyles(themeService); // every so many events we check if there are // css styles that we don't need anymore let count = 0; - this._register(this.onDidChangeDecorations(() => { + let reg = this.onDidChangeDecorations(() => { if (++count % 17 === 0) { this._decorationStyles.cleanUp(this._data.iterator()); } - })); + }); + + this._disposables = [ + reg, + this._decorationStyles + ]; + } + + dispose(): void { + dispose(this._disposables); + dispose(this._onDidChangeDecorations); + dispose(this._onDidChangeDecorationsDelayed); } registerDecorationsProvider(provider: IDecorationsProvider): IDisposable { diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index fe43bbd5c3b..f7d1e60691e 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -91,7 +91,8 @@ export class FileDialogService implements IFileDialogService { } private ensureFileSchema(schema: string): string[] { - return schema !== Schemas.file ? [schema, Schemas.file] : [schema]; + // Don't allow untitled schema through. + return schema === Schemas.untitled ? [Schemas.file] : (schema !== Schemas.file ? [schema, Schemas.file] : [schema]); } async pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { @@ -207,6 +208,7 @@ export class FileDialogService implements IFileDialogService { } private toNativeSaveDialogOptions(options: ISaveDialogOptions): Electron.SaveDialogOptions { + options.defaultUri = options.defaultUri ? URI.file(options.defaultUri.path) : undefined; return { defaultPath: options.defaultUri && options.defaultUri.fsPath, buttonLabel: options.saveLabel, @@ -219,7 +221,7 @@ export class FileDialogService implements IFileDialogService { const schema = this.getFileSystemSchema(options); if (this.shouldUseSimplified(schema)) { if (!options.availableFileSystems) { - options.availableFileSystems = [schema]; // by default only allow saving in the own file system + options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well } return this.saveRemoteResource(options); @@ -237,7 +239,7 @@ export class FileDialogService implements IFileDialogService { const schema = this.getFileSystemSchema(options); if (this.shouldUseSimplified(schema)) { if (!options.availableFileSystems) { - options.availableFileSystems = [schema]; // by default only allow loading in the own file system + options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well } const uri = await this.pickRemoteResource(options); @@ -286,12 +288,12 @@ export class FileDialogService implements IFileDialogService { return remoteFileDialog.showSaveDialog(options); } - private getSchemeFilterForWindow() { + private getSchemeFilterForWindow(): string { return !this.environmentService.configuration.remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; } private getFileSystemSchema(options: { availableFileSystems?: string[], defaultUri?: URI }): string { - return options.availableFileSystems && options.availableFileSystems[0] || options.defaultUri && options.defaultUri.scheme || this.getSchemeFilterForWindow(); + return options.availableFileSystems && options.availableFileSystems[0] || this.getSchemeFilterForWindow(); } } diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index 7e30aabf598..7c70bf3fecb 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -30,6 +30,8 @@ import { isValidBasename } from 'vs/base/common/extpath'; import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; import { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async'; +import { CancellationToken } from 'vs/base/common/cancellation'; interface FileQuickPickItem extends IQuickPickItem { uri: URI; @@ -63,6 +65,7 @@ export class RemoteFileDialog { private remoteAgentEnvironment: IRemoteAgentEnvironment | null; private separator: string; private onBusyChangeEmitter = new Emitter(); + private updatingPromise: CancelablePromise | undefined; protected disposables: IDisposable[] = [ this.onBusyChangeEmitter @@ -212,7 +215,7 @@ export class RemoteFileDialog { this.filePickBox.autoFocusOnList = false; this.filePickBox.ignoreFocusOut = true; this.filePickBox.ok = true; - if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) { + if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) { this.filePickBox.customButton = true; this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local'); let action; @@ -232,7 +235,7 @@ export class RemoteFileDialog { let isResolving: number = 0; let isAcceptHandled = false; - this.currentFolder = homedir; + this.currentFolder = resources.dirname(homedir); this.userEnteredPathSegment = ''; this.autoCompletePathSegment = ''; @@ -707,25 +710,41 @@ export class RemoteFileDialog { this.autoCompletePathSegment = ''; const newValue = trailing ? this.pathAppend(newFolder, trailing) : this.pathFromUri(newFolder, true); this.currentFolder = resources.addTrailingPathSeparator(newFolder, this.separator); - return this.createItems(this.currentFolder).then(items => { - this.filePickBox.items = items; - if (this.allowFolderSelection) { - this.filePickBox.activeItems = []; - } - // the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory. - if (!equalsIgnoreCase(this.filePickBox.value, newValue) && force) { - this.filePickBox.valueSelection = [0, this.filePickBox.value.length]; - this.insertText(newValue, newValue); - } - if (force && trailing) { - // Keep the cursor position in front of the save as name. - this.filePickBox.valueSelection = [this.filePickBox.value.length - trailing.length, this.filePickBox.value.length - trailing.length]; - } else if (!trailing) { - // If there is trailing, we don't move the cursor. If there is no trailing, cursor goes at the end. - this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; - } - this.busy = false; + + const updatingPromise = createCancelablePromise(async token => { + return this.createItems(this.currentFolder, token).then(items => { + if (token.isCancellationRequested) { + this.busy = false; + return; + } + + this.filePickBox.items = items; + if (this.allowFolderSelection) { + this.filePickBox.activeItems = []; + } + // the user might have continued typing while we were updating. Only update the input box if it doesn't matche directory. + if (!equalsIgnoreCase(this.filePickBox.value, newValue) && force) { + this.filePickBox.valueSelection = [0, this.filePickBox.value.length]; + this.insertText(newValue, newValue); + } + if (force && trailing) { + // Keep the cursor position in front of the save as name. + this.filePickBox.valueSelection = [this.filePickBox.value.length - trailing.length, this.filePickBox.value.length - trailing.length]; + } else if (!trailing) { + // If there is trailing, we don't move the cursor. If there is no trailing, cursor goes at the end. + this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; + } + this.busy = false; + this.updatingPromise = undefined; + }); }); + + if (this.updatingPromise !== undefined) { + this.updatingPromise.cancel(); + } + this.updatingPromise = updatingPromise; + + return updatingPromise; } private pathFromUri(uri: URI, endWithSeparator: boolean = false): string { @@ -777,14 +796,14 @@ export class RemoteFileDialog { return null; } - private async createItems(currentFolder: URI): Promise { + private async createItems(currentFolder: URI, token: CancellationToken): Promise { const result: FileQuickPickItem[] = []; const backDir = this.createBackItem(currentFolder); try { const folder = await this.fileService.resolve(currentFolder); const fileNames = folder.children ? folder.children.map(child => child.name) : []; - const items = await Promise.all(fileNames.map(fileName => this.createItem(fileName, currentFolder))); + const items = await Promise.all(fileNames.map(fileName => this.createItem(fileName, currentFolder, token))); for (let item of items) { if (item) { result.push(item); @@ -794,6 +813,9 @@ export class RemoteFileDialog { // ignore console.log(e); } + if (token.isCancellationRequested) { + return []; + } const sorted = result.sort((i1, i2) => { if (i1.isFolder !== i2.isFolder) { return i1.isFolder ? -1 : 1; @@ -824,7 +846,10 @@ export class RemoteFileDialog { return true; } - private async createItem(filename: string, parent: URI): Promise { + private async createItem(filename: string, parent: URI, token: CancellationToken): Promise { + if (token.isCancellationRequested) { + return undefined; + } let fullPath = resources.joinPath(parent, filename); try { const stat = await this.fileService.resolve(fullPath); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 3211d6adeb4..444045e8825 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -27,7 +27,7 @@ import { isCodeEditor, isDiffEditor, ICodeEditor, IDiffEditor } from 'vs/editor/ import { IEditorGroupView, IEditorOpeningEvent, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { ILabelService } from 'vs/platform/label/common/label'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { withNullAsUndefined } from 'vs/base/common/types'; type ICachedEditorInput = ResourceEditorInput | IFileEditorInput | DataUriEditorInput; @@ -40,16 +40,16 @@ export class EditorService extends Disposable implements EditorServiceImpl { //#region events private readonly _onDidActiveEditorChange: Emitter = this._register(new Emitter()); - get onDidActiveEditorChange(): Event { return this._onDidActiveEditorChange.event; } + readonly onDidActiveEditorChange: Event = this._onDidActiveEditorChange.event; private readonly _onDidVisibleEditorsChange: Emitter = this._register(new Emitter()); - get onDidVisibleEditorsChange(): Event { return this._onDidVisibleEditorsChange.event; } + readonly onDidVisibleEditorsChange: Event = this._onDidVisibleEditorsChange.event; private readonly _onDidCloseEditor: Emitter = this._register(new Emitter()); - get onDidCloseEditor(): Event { return this._onDidCloseEditor.event; } + readonly onDidCloseEditor: Event = this._onDidCloseEditor.event; private readonly _onDidOpenEditorFail: Emitter = this._register(new Emitter()); - get onDidOpenEditorFail(): Event { return this._onDidOpenEditorFail.event; } + readonly onDidOpenEditorFail: Event = this._onDidOpenEditorFail.event; //#endregion @@ -503,7 +503,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Side by Side Support - const resourceSideBySideInput = input; + const resourceSideBySideInput = input as IResourceSideBySideInput; if (resourceSideBySideInput.masterResource && resourceSideBySideInput.detailResource) { const masterInput = this.createInput({ resource: resourceSideBySideInput.masterResource, forceFile: resourceSideBySideInput.forceFile }); const detailInput = this.createInput({ resource: resourceSideBySideInput.detailResource, forceFile: resourceSideBySideInput.forceFile }); @@ -518,23 +518,23 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Diff Editor Support - const resourceDiffInput = input; + const resourceDiffInput = input as IResourceDiffInput; if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { const leftInput = this.createInput({ resource: resourceDiffInput.leftResource, forceFile: resourceDiffInput.forceFile }); const rightInput = this.createInput({ resource: resourceDiffInput.rightResource, forceFile: resourceDiffInput.forceFile }); const label = resourceDiffInput.label || localize('compareLabels', "{0} ↔ {1}", this.toDiffLabel(leftInput), this.toDiffLabel(rightInput)); - return new DiffEditorInput(label, withUndefinedAsNull(resourceDiffInput.description), leftInput, rightInput); + return new DiffEditorInput(label, resourceDiffInput.description, leftInput, rightInput); } // Untitled file support - const untitledInput = input; + const untitledInput = input as IUntitledResourceInput; if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource && untitledInput.resource.scheme === Schemas.untitled)) { return this.untitledEditorService.createOrGet(untitledInput.resource, untitledInput.mode, untitledInput.contents, untitledInput.encoding); } // Resource Editor Support - const resourceInput = input; + const resourceInput = input as IResourceInput; if (resourceInput.resource instanceof URI) { let label = resourceInput.label; if (!label && resourceInput.resource.scheme !== Schemas.data) { diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 91b2ea587f3..a9ab498cc98 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -179,7 +179,7 @@ export interface IEditorGroupsService { /** * The size of the editor groups area. */ - readonly dimension: IDimension; + readonly contentDimension: IDimension; /** * An active group is the default location for new editors to open. @@ -232,12 +232,12 @@ export interface IEditorGroupsService { /** * Returns the size of a group. */ - getSize(group: IEditorGroup | GroupIdentifier): number; + getSize(group: IEditorGroup | GroupIdentifier): { width: number, height: number }; /** * Sets the size of a group. */ - setSize(group: IEditorGroup | GroupIdentifier, size: number): void; + setSize(group: IEditorGroup | GroupIdentifier, size: { width: number, height: number }): void; /** * Arrange all groups according to the provided arrangement. @@ -411,7 +411,7 @@ export interface IEditorGroup { /** * Returns the editor at a specific index of the group. */ - getEditor(index: number): IEditorInput | null; + getEditor(index: number): IEditorInput | undefined; /** * Get all editors that are currently opened in the group optionally diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 28720257840..477fdfc5bc7 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -80,7 +80,7 @@ suite('EditorGroupsService', () => { } (Registry.as(EditorExtensions.EditorInputFactories)).registerEditorInputFactory('testEditorInputForGroupsService', TestEditorInputFactory); - (Registry.as(Extensions.Editors)).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), new SyncDescriptor(TestEditorInput)); + (Registry.as(Extensions.Editors)).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), [new SyncDescriptor(TestEditorInput)]); } registerTestEditorInput(); @@ -118,11 +118,6 @@ suite('EditorGroupsService', () => { groupMovedCounter++; }); - let preferredSizeChangeCounter = 0; - const preferredSizeChangeListener = part.onDidPreferredSizeChange(() => { - preferredSizeChangeCounter++; - }); - // always a root group const rootGroup = part.groups[0]; assert.equal(part.groups.length, 1); @@ -141,7 +136,6 @@ suite('EditorGroupsService', () => { assert.equal(part.groups.length, 2); assert.equal(part.count, 2); assert.ok(part.activeGroup === rootGroup); - assert.equal(preferredSizeChangeCounter, 1); assert.equal(rootGroup.label, 'Group 1'); assert.equal(rightGroup.label, 'Group 2'); @@ -189,7 +183,6 @@ suite('EditorGroupsService', () => { assert.equal(part.groups.length, 3); assert.ok(part.activeGroup === rightGroup); assert.ok(!downGroup.activeControl); - assert.equal(preferredSizeChangeCounter, 2); assert.equal(rootGroup.label, 'Group 1'); assert.equal(rightGroup.label, 'Group 2'); assert.equal(downGroup.label, 'Group 3'); @@ -208,13 +201,11 @@ suite('EditorGroupsService', () => { part.moveGroup(downGroup, rightGroup, GroupDirection.DOWN); assert.equal(groupMovedCounter, 1); - assert.equal(preferredSizeChangeCounter, 2); part.removeGroup(downGroup); assert.ok(!part.getGroup(downGroup.id)); assert.equal(didDispose, true); assert.equal(groupRemovedCounter, 1); - assert.equal(preferredSizeChangeCounter, 3); assert.equal(part.groups.length, 2); assert.ok(part.activeGroup === rightGroup); assert.equal(rootGroup.label, 'Group 1'); @@ -254,13 +245,11 @@ suite('EditorGroupsService', () => { assert.ok(part.activeGroup === rootGroup); part.setGroupOrientation(part.orientation === GroupOrientation.HORIZONTAL ? GroupOrientation.VERTICAL : GroupOrientation.HORIZONTAL); - assert.equal(preferredSizeChangeCounter, 5); activeGroupChangeListener.dispose(); groupAddedListener.dispose(); groupRemovedListener.dispose(); groupMovedListener.dispose(); - preferredSizeChangeListener.dispose(); part.dispose(); }); diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 658a4a84e77..913a95d4aa1 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -8,7 +8,7 @@ import { IEditorModel } from 'vs/platform/editor/common/editor'; import { URI } from 'vs/base/common/uri'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, IFileEditorInput, IEditorInput } from 'vs/workbench/common/editor'; -import { workbenchInstantiationService, TestStorageService, NullFileSystemProvider } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { EditorService, DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService'; @@ -31,6 +31,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; +import { NullFileSystemProvider } from 'vs/platform/files/test/common/nullFileSystemProvider'; export class TestEditorControl extends BaseEditor { @@ -82,7 +83,7 @@ class FileServiceProvider extends Disposable { suite('EditorService', () => { function registerTestEditorInput(): void { - Registry.as(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), new SyncDescriptor(TestEditorInput)); + Registry.as(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), [new SyncDescriptor(TestEditorInput)]); } registerTestEditorInput(); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 98ecb8d6935..2bd39c97554 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; @@ -111,8 +141,6 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService { localeResource: URI; machineSettingsHome: URI; machineSettingsResource: URI; - settingsSearchBuildId?: number; - settingsSearchUrl?: string; globalStorageHome: string; workspaceStorageHome: string; backupHome: URI; @@ -121,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; @@ -145,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 4e1a3788010..3ceb5b20856 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 00000000000..bd16a2ca85b --- /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 MIT License. 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 00000000000..0a48d2989fb --- /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 MIT License. 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 69% rename from src/vs/workbench/services/extensions/node/multiExtensionManagement.ts rename to src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 1760b4d5fc3..337f52b278a 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; } @@ -125,7 +130,11 @@ export class MultiExtensionManagementService extends Disposable implements IExte } zip(extension: ILocalExtension): Promise { - throw new Error('Not Supported'); + const server = this.getServer(extension); + if (server) { + return server.extensionManagementService.zip(extension); + } + return Promise.reject(`Invalid location ${extension.location.toString()}`); } unzip(zipLocation: URI, type: ExtensionType): Promise { @@ -133,25 +142,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 +169,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); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts similarity index 81% rename from src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts rename to src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts index 611ab9aec95..c3921f17a54 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 00000000000..46db06b9d1a --- /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 MIT License. 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 cdb4509a617..5852ce2d53c 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 23fa0b21c4a..077598d16d6 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'; @@ -14,7 +14,6 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IProductService } from 'vs/platform/product/common/product'; import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService'; -import { browserWebSocketFactory } from 'vs/platform/remote/browser/browserWebSocketFactory'; import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; @@ -63,7 +62,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const result: ExtensionHostProcessManager[] = []; const remoteAgentConnection = this._remoteAgentService.getConnection()!; - const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), browserWebSocketFactory); + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); result.push(remoteExtHostProcessManager); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index d57fa8b1801..eed7a616357 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'; @@ -51,7 +51,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx private readonly _installedExtensionsReady: Barrier; protected readonly _isDev: boolean; private readonly _extensionsMessages: Map; - protected readonly _allRequestedActivateEvents: { [activationEvent: string]: boolean; }; + protected readonly _allRequestedActivateEvents = new Set(); private readonly _proposedApiController: ProposedApiController; private readonly _isExtensionDevHost: boolean; protected readonly _isExtensionDevTestFromCli: boolean; @@ -82,7 +82,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx this._installedExtensionsReady = new Barrier(); this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; this._extensionsMessages = new Map(); - this._allRequestedActivateEvents = Object.create(null); this._proposedApiController = new ProposedApiController(this._environmentService, this._productService); this._extensionHostProcessManagers = []; @@ -168,11 +167,11 @@ export abstract class AbstractExtensionService extends Disposable implements IEx public restartExtensionHost(): void { this._stopExtensionHostProcess(); - this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); + this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys())); } public startExtensionHost(): void { - this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); + this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys())); } public stopExtensionHost(): void { @@ -184,7 +183,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx // Extensions have been scanned and interpreted // Record the fact that this activationEvent was requested (in case of a restart) - this._allRequestedActivateEvents[activationEvent] = true; + this._allRequestedActivateEvents.add(activationEvent); if (!this._registry.containsActivationEvent(activationEvent)) { // There is no extension that is interested in this activation event @@ -196,7 +195,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx // Extensions have not been scanned yet. // Record the fact that this activationEvent was requested (in case of a restart) - this._allRequestedActivateEvents[activationEvent] = true; + this._allRequestedActivateEvents.add(activationEvent); return this._installedExtensionsReady.wait().then(() => this._activateByEvent(activationEvent)); } diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index c3f651cd23f..21cddb13749 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -14,7 +14,7 @@ import { ExtHostCustomersRegistry } from 'vs/workbench/api/common/extHostCustome import { ExtHostContext, ExtHostExtensionServiceShape, IExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; -import { ResolvedAuthority, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; @@ -247,15 +247,17 @@ export class ExtensionHostProcessManager extends Disposable { return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort()); } - public async resolveAuthority(remoteAuthority: string): Promise { + public async resolveAuthority(remoteAuthority: string): Promise { const authorityPlusIndex = remoteAuthority.indexOf('+'); if (authorityPlusIndex === -1) { // This authority does not need to be resolved, simply parse the port number const pieces = remoteAuthority.split(':'); return Promise.resolve({ - authority: remoteAuthority, - host: pieces[0], - port: parseInt(pieces[1], 10) + authority: { + authority: remoteAuthority, + host: pieces[0], + port: parseInt(pieces[1], 10) + } }); } const proxy = await this._getExtensionHostProcessProxy(); diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index 351bbe5ddc9..7330ceedefb 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -7,8 +7,10 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; 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'; @@ -22,6 +24,8 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const FIVE_MINUTES = 5 * 60 * 1000; const THIRTY_SECONDS = 30 * 1000; const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle'; +const CONFIRMED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds'; +const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions'; function isExtensionId(value: string): boolean { return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value); @@ -61,7 +65,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IWindowService private readonly windowService: IWindowService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @IStorageService private readonly storageService: IStorageService + @IStorageService private readonly storageService: IStorageService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { const interval = setInterval(() => this.garbageCollect(), THIRTY_SECONDS); const urlToHandleValue = this.storageService.get(URL_TO_HANDLE, StorageScope.WORKSPACE); @@ -90,6 +96,11 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return true; } + if (!confirmed) { + const confirmedExtensionIds = this.getConfirmedExtensionIds(); + confirmed = confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); + } + if (!confirmed) { let uriString = uri.toString(); @@ -99,6 +110,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { const result = await this.dialogService.confirm({ message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), + checkbox: { + label: localize('rememberConfirmUrl', "Don't ask again for this extension."), + }, detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' @@ -107,6 +121,10 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { if (!result.confirmed) { return true; } + + if (result.checkboxChecked) { + this.addConfirmedExtensionIdToStorage(extensionId); + } } const handler = this.extensionHandlers.get(ExtensionIdentifier.toKey(extensionId)); @@ -190,7 +208,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); } } @@ -266,6 +284,47 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.uriBuffer = uriBuffer; } + private getConfirmedExtensionIds(): Set { + const ids = [ + ...this.getConfirmedExtensionIdsFromStorage(), + ...this.getConfirmedExtensionIdsFromConfiguration(), + ].map(extensionId => ExtensionIdentifier.toKey(extensionId)); + + return new Set(ids); + } + + private getConfirmedExtensionIdsFromConfiguration(): Array { + const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); + + if (!Array.isArray(confirmedExtensionIds)) { + return []; + } + + return confirmedExtensionIds; + } + + private getConfirmedExtensionIdsFromStorage(): Array { + const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + + try { + return JSON.parse(confirmedExtensionIdsJson); + } catch (err) { + return []; + } + } + + private addConfirmedExtensionIdToStorage(extensionId: string): void { + const existingConfirmedExtensionIds = this.getConfirmedExtensionIdsFromStorage(); + this.storageService.store( + CONFIRMED_EXTENSIONS_STORAGE_KEY, + JSON.stringify([ + ...existingConfirmedExtensionIds, + ExtensionIdentifier.toKey(extensionId), + ]), + StorageScope.GLOBAL, + ); + } + dispose(): void { this.disposable.dispose(); this.extensionHandlers.clear(); diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts index 9dc5b940cf1..037a2534d92 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -8,7 +8,7 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; -import { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions, IWebSocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; +import { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; @@ -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'; @@ -47,7 +47,7 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH constructor( private readonly _allExtensions: Promise, private readonly _initDataProvider: IInitDataProvider, - private readonly _webSocketFactory: IWebSocketFactory, + private readonly _socketFactory: ISocketFactory, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @@ -73,22 +73,23 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH const options: IConnectionOptions = { isBuilt: this._environmentService.isBuilt, commit: this._productService.commit, - webSocketFactory: this._webSocketFactory, + socketFactory: this._socketFactory, addressProvider: { getAddress: async () => { - const { host, port } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority); - return { host, port }; + const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority); + return { host: authority.host, port: authority.port }; } }, signService: this._signService }; - return this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority).then((resolvedAuthority) => { + return this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority).then((resolverResult) => { const startParams: IRemoteExtensionHostStartParams = { language: platform.language, debugId: this._environmentService.debugExtensionHost.debugId, break: this._environmentService.debugExtensionHost.break, port: this._environmentService.debugExtensionHost.port, + env: resolverResult.options && resolverResult.options.extensionHostEnv }; const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; @@ -161,6 +162,11 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH } private _onExtHostConnectionLost(): void { + + if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId) { + this._extensionHostDebugService.close(this._environmentService.debugExtensionHost.debugId); + } + if (this._terminating) { // Expected termination path (we asked the process to terminate) return; diff --git a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts index f24f320674b..10fd66cbdc9 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'; @@ -101,10 +101,6 @@ export class CachedExtensionScanner { development.forEach(developedExtension => { log.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath)); const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier); - const extension = result.get(extensionKey); - if (extension) { - log.warn(developedExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, developedExtension.extensionLocation.fsPath)); - } result.set(extensionKey, developedExtension); }); let r: IExtensionDescription[] = []; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 7b8225ca6ac..923130c9ee3 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'; @@ -434,7 +434,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(entry.severity, ...parse(entry).args); + this._windowsService.log(entry.severity, parse(entry).args); } // Broadcast to other windows if we are in development mode diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts index aa4a35f54dd..e292a9ecd31 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 MIT License. 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 98b5cf01ba1..6fb7d2d1be1 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -7,18 +7,18 @@ import { ipcRenderer as ipc } from 'electron'; import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService'; import * as nls from 'vs/nls'; 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'; -import { IRemoteAuthorityResolverService, ResolvedAuthority, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -31,7 +31,7 @@ import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/co import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Schemas } from 'vs/base/common/network'; import { IFileService } from 'vs/platform/files/common/files'; -import { PersistenConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; +import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; import { IProductService } from 'vs/platform/product/common/product'; import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints'; @@ -202,6 +202,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten // Update the local registry const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier)); + this._onDidChangeExtensions.fire(undefined); + toRemove = toRemove.concat(result.removedDueToLooping); if (result.removedDueToLooping.length > 0) { this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); @@ -218,8 +220,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten await this._extensionHostProcessManagers[0].deltaExtensions(toAdd, toRemove.map(e => e.identifier)); } - this._onDidChangeExtensions.fire(undefined); - for (let i = 0; i < toAdd.length; i++) { this._activateAddedExtensionIfNeeded(toAdd[i]); } @@ -294,7 +294,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`; } - if (this._allRequestedActivateEvents[activationEvent]) { + if (this._allRequestedActivateEvents.has(activationEvent)) { // This activation event was fired before the extension was added shouldActivate = true; shouldActivateReason = activationEvent; @@ -355,7 +355,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const remoteAgentConnection = this._remoteAgentService.getConnection(); if (remoteAgentConnection) { - const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), nodeWebSocketFactory); + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); result.push(remoteExtHostProcessManager); } @@ -418,8 +418,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten const extensionHost = this._extensionHostProcessManagers[0]; this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority); try { - const resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority); - this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority); + const result = await extensionHost.resolveAuthority(remoteAuthority); + this._remoteAuthorityResolverService.setResolvedAuthority(result.authority, result.options); } catch (err) { this._remoteAuthorityResolverService.setResolvedAuthorityError(remoteAuthority, err); } @@ -440,7 +440,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten localExtensions = localExtensions.filter(extension => this._isEnabled(extension)); if (remoteAuthority) { - let resolvedAuthority: ResolvedAuthority; + let resolvedAuthority: ResolverResult; try { resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority); @@ -462,7 +462,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten } // set the resolved authority - this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority); + this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority.authority, resolvedAuthority.options); // monitor for breakage const connection = this._remoteAgentService.getConnection(); @@ -472,7 +472,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten if (!remoteAuthority) { return; } - if (e.type === PersistenConnectionEventType.ConnectionLost) { + if (e.type === PersistentConnectionEventType.ConnectionLost) { this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority); } }); diff --git a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts index 6fd6dc821e8..84ec145c4c8 100644 --- a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts +++ b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { tmpdir } from 'os'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; @@ -17,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 { @@ -79,8 +80,8 @@ export class RemoteExtensionManagementChannelClient extends ExtensionManagementC } private async downloadAndInstall(extension: IGalleryExtension, installed: ILocalExtension[]): Promise { - const location = await this.galleryService.download(extension, installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install); - return super.install(URI.file(location)); + const location = await this.galleryService.download(extension, URI.file(tmpdir()), installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install); + return super.install(location); } private async installUIDependenciesAndPackedExtensions(local: ILocalExtension): Promise { diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 6a1083c003b..5a7efd1462b 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'; @@ -13,7 +13,7 @@ import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { getGalleryExtensionId, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { isValidExtensionVersion } from 'vs/platform/extensions/node/extensionValidator'; +import { isValidExtensionVersion } from 'vs/platform/extensions/common/extensionValidator'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints'; diff --git a/src/vs/workbench/services/files/common/workspaceWatcher.ts b/src/vs/workbench/services/files/common/workspaceWatcher.ts index a16c82e3594..7aa7ef157f6 100644 --- a/src/vs/workbench/services/files/common/workspaceWatcher.ts +++ b/src/vs/workbench/services/files/common/workspaceWatcher.ts @@ -16,7 +16,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { localize } from 'vs/nls'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; export class WorkspaceWatcher extends Disposable { diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 4e64ebdc0c6..dec59cfca2c 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -300,7 +300,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { // This might be a removal keybinding item in user settings => accept it @@ -323,7 +323,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private _resolveUserKeybindingItems(items: IUserKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const parts = item.parts; if (parts.length === 0) { // This might be a removal keybinding item in user settings => accept it diff --git a/src/vs/workbench/services/keybinding/browser/keymapService.ts b/src/vs/workbench/services/keybinding/browser/keymapService.ts index 401dede8db9..a0d6e007f79 100644 --- a/src/vs/workbench/services/keybinding/browser/keymapService.ts +++ b/src/vs/workbench/services/keybinding/browser/keymapService.ts @@ -200,6 +200,8 @@ export class BrowserKeyboardMapperFactoryBase { }] ); + console.warn('Active keymap/keyevent does not match current keyboard layout', JSON.stringify(keymap), this._activeKeymapInfo ? JSON.stringify(this._activeKeymapInfo.layout) : ''); + return; } diff --git a/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts index acf45e1358d..70c6b1dd926 100644 --- a/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts @@ -12,33 +12,39 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; class TestKeyboardMapperFactory extends BrowserKeyboardMapperFactoryBase { constructor(notificationService: INotificationService, storageService: IStorageService, commandService: ICommandService) { super(notificationService, storageService, commandService); - let keymapInfos: IKeymapInfo[] = KeyboardLayoutContribution.INSTANCE.layoutInfos; + const keymapInfos: IKeymapInfo[] = KeyboardLayoutContribution.INSTANCE.layoutInfos; this._keymapInfos.push(...keymapInfos.map(info => (new KeymapInfo(info.layout, info.secondaryLayouts, info.mapping, info.isUserKeyboardLayout)))); this._mru = this._keymapInfos; this._initialized = true; this.onKeyboardLayoutChanged(); + const usLayout = this.getUSStandardLayout(); + if (usLayout) { + this.setActiveKeyMapping(usLayout.mapping); + } } } - suite('keyboard layout loader', () => { let instantiationService: TestInstantiationService = new TestInstantiationService(); - let notitifcationService = instantiationService.stub(INotificationService, {}); - let storageService = instantiationService.stub(IStorageService, {}); + let notitifcationService = instantiationService.stub(INotificationService, new TestNotificationService()); + let storageService = instantiationService.stub(IStorageService, new TestStorageService()); + let commandService = instantiationService.stub(ICommandService, {}); let instance = new TestKeyboardMapperFactory(notitifcationService, storageService, commandService); - test.skip('load default US keyboard layout', () => { + test('load default US keyboard layout', () => { assert.notEqual(instance.activeKeyboardLayout, null); assert.equal(instance.activeKeyboardLayout!.isUSStandard, true); }); - test.skip('isKeyMappingActive', () => { + test('isKeyMappingActive', () => { assert.equal(instance.isKeyMappingActive({ KeyA: { value: 'a', diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index c6599181ee5..4ae911b01ff 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -41,9 +41,9 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestTextFileService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { URI } from 'vs/base/common/uri'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; import { parseArgs } from 'vs/platform/environment/node/argv'; diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index d0bf836984f..344c7657de5 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; +import { Dimension } from 'vs/base/browser/dom'; export const IWorkbenchLayoutService = createDecorator('layoutService'); @@ -81,6 +82,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ isVisible(part: Parts): boolean; + /** + * Returns if the part is visible. + */ + getDimension(part: Parts): Dimension; + /** * Set activity bar hidden or not */ diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 75c7be48efc..8788a416741 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -91,11 +91,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic private readonly defaultSettingsRawResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/defaultSettings.json' }); get userSettingsResource(): URI { - return this.getEditableSettingsURI(ConfigurationTarget.USER)!; + return this.environmentService.settingsResource; } get workspaceSettingsResource(): URI | null { - return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + return null; + } + const workspace = this.contextService.getWorkspace(); + return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); } get settingsEditor2Input(): SettingsEditor2Input { @@ -103,7 +107,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic } getFolderSettingsResource(resource: URI): URI | null { - return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); + const folder = this.contextService.getWorkspaceFolder(resource); + return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; } resolveModel(uri: URI): Promise { @@ -153,7 +158,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return Promise.resolve(null); } - createPreferencesEditorModel(uri: URI): Promise> { + async createPreferencesEditorModel(uri: URI): Promise | null> { if (this.isDefaultSettingsResource(uri)) { return this.createDefaultSettingsEditorModel(uri); } @@ -162,16 +167,25 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_LOCAL, uri); } - const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); + const workspaceSettingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri); } if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); + const settingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, uri); + if (settingsUri && settingsUri.toString() === uri.toString()) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); + } } - return Promise.reject(`unknown resource: ${uri.toString()}`); + const remoteEnvironment = await this.remoteAgentService.getEnvironment(); + const remoteSettingsUri = remoteEnvironment ? remoteEnvironment.settingsPath : null; + if (remoteSettingsUri && remoteSettingsUri.toString() === uri.toString()) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_REMOTE, uri); + } + + return null; } openRawDefaultSettings(): Promise { @@ -237,11 +251,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE, undefined, options, group); } - openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { + async openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { jsonEditor = typeof jsonEditor === 'undefined' ? this.configurationService.getValue('workbench.settings.editor') === 'json' : jsonEditor; - const folderSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); + const folderSettingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); if (jsonEditor) { if (folderSettingsUri) { return this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, folderSettingsUri, options, group); @@ -389,8 +403,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.editorService.openEditor(input, SettingsEditorOptions.create(settingsOptions), group); } - private doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { - const settingsURI = this.getEditableSettingsURI(target, resource); + private async doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { + const settingsURI = await this.getEditableSettingsURI(target, resource); if (!settingsURI) { return Promise.reject(`Invalid settings URI - ${resource.toString()}`); } @@ -477,18 +491,14 @@ export class PreferencesService extends Disposable implements IPreferencesServic .then(() => this.editorService.createInput({ resource })); } - private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): Promise { - const settingsUri = this.getEditableSettingsURI(configurationTarget, resource); - if (settingsUri) { - const workspace = this.contextService.getWorkspace(); - if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { - return this.textModelResolverService.createModelReference(settingsUri) - .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); - } + private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, settingsUri: URI): Promise { + const workspace = this.contextService.getWorkspace(); + if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { return this.textModelResolverService.createModelReference(settingsUri) - .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); + .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); } - return Promise.reject(`unknown target: ${configurationTarget} and resource: ${resource.toString()}`); + return this.textModelResolverService.createModelReference(settingsUri) + .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); } private createDefaultSettingsEditorModel(defaultSettingsUri: URI): Promise { @@ -518,23 +528,19 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this._defaultUserSettingsContentModel; } - private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI | null { + private async getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): Promise { switch (configurationTarget) { case ConfigurationTarget.USER: case ConfigurationTarget.USER_LOCAL: - return this.environmentService.settingsResource; + return this.userSettingsResource; case ConfigurationTarget.USER_REMOTE: - return this.environmentService.settingsResource; + const remoteEnvironment = await this.remoteAgentService.getEnvironment(); + return remoteEnvironment ? remoteEnvironment.settingsPath : null; case ConfigurationTarget.WORKSPACE: - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - return null; - } - const workspace = this.contextService.getWorkspace(); - return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); + return this.workspaceSettingsResource; case ConfigurationTarget.WORKSPACE_FOLDER: if (resource) { - const folder = this.contextService.getWorkspaceFolder(resource); - return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; + return this.getFolderSettingsResource(resource); } } return null; diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index 008d85de813..abf288178cc 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -25,6 +25,7 @@ export enum SettingValueType { Integer = 'integer', Number = 'number', Boolean = 'boolean', + ArrayOfString = 'array-of-string', Exclude = 'exclude', Complex = 'complex', NullableInteger = 'nullable-integer', @@ -61,6 +62,7 @@ export interface ISetting { scope?: ConfigurationScope; type?: string | string[]; + arrayItemType?: string; enum?: string[]; enumDescriptions?: string[]; enumDescriptionsAreMarkdown?: boolean; @@ -196,7 +198,7 @@ export interface IPreferencesService { getFolderSettingsResource(resource: URI): URI | null; resolveModel(uri: URI): Promise; - createPreferencesEditorModel(uri: URI): Promise>; + createPreferencesEditorModel(uri: URI): Promise | null>; createSettings2EditorModel(): Settings2EditorModel; // TODO openRawDefaultSettings(): Promise; diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 121cfeb9f37..d24d2a53f68 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -22,7 +22,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorModel } from 'vs/workbench/common/editor'; import { IFilterMetadata, IFilterResult, IGroupFilter, IKeybindingsEditorModel, ISearchResultGroup, ISetting, ISettingMatch, ISettingMatcher, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, isArray } from 'vs/base/common/types'; export const nullRange: IRange = { startLineNumber: -1, startColumn: -1, endLineNumber: -1, endColumn: -1 }; export function isNullRange(range: IRange): boolean { return range.startLineNumber === -1 && range.startColumn === -1 && range.endLineNumber === -1 && range.endColumn === -1; } @@ -375,6 +375,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, const position = model.getPositionAt(offset); range.endLineNumber = position.lineNumber; range.endColumn = position.column; + settingsPropertyIndex = -1; } }, onArrayBegin: (offset: number, length: number) => { @@ -613,6 +614,10 @@ export class DefaultSettings extends Disposable { const value = prop.default; const description = (prop.description || prop.markdownDescription || '').split('\n'); const overrides = OVERRIDE_PROPERTY_PATTERN.test(key) ? this.parseOverrideSettings(prop.default) : []; + const listItemType = prop.type === 'array' && prop.items && !isArray(prop.items) && prop.items.type && !isArray(prop.items.type) + ? prop.items.type + : undefined; + result.push({ key, value, @@ -625,6 +630,7 @@ export class DefaultSettings extends Disposable { overrides, scope: prop.scope, type: prop.type, + arrayItemType: listItemType, enum: prop.enum, enumDescriptions: prop.enumDescriptions || prop.markdownEnumDescriptions, enumDescriptionsAreMarkdown: !prop.enumDescriptions, diff --git a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts index ee8b3c9b9d2..4219ca53901 100644 --- a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts @@ -4,18 +4,22 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; import { IProductService } from 'vs/platform/product/common/product'; -import { browserWebSocketFactory } from 'vs/platform/remote/browser/browserWebSocketFactory'; +import { IWebSocketFactory, BrowserSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; +import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; -export class RemoteAgentService extends AbstractRemoteAgentService { +export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService { + + public readonly socketFactory: ISocketFactory; private readonly _connection: IRemoteAgentConnection | null = null; constructor( + webSocketFactory: IWebSocketFactory | null | undefined, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IProductService productService: IProductService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, @@ -23,7 +27,8 @@ export class RemoteAgentService extends AbstractRemoteAgentService { ) { super(environmentService); - this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, browserWebSocketFactory, environmentService, remoteAuthorityResolverService, signService)); + this.socketFactory = new BrowserSocketFactory(webSocketFactory); + this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, this.socketFactory, environmentService, remoteAuthorityResolverService, signService)); } getConnection(): IRemoteAgentConnection | null { diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts index c5ece27cfb2..e48834a6a6b 100644 --- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { connectRemoteAgentManagement, IConnectionOptions, IWebSocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; +import { connectRemoteAgentManagement, IConnectionOptions, ISocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; @@ -21,7 +21,7 @@ import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics import { Emitter } from 'vs/base/common/event'; import { ISignService } from 'vs/platform/sign/common/sign'; -export abstract class AbstractRemoteAgentService extends Disposable implements IRemoteAgentService { +export abstract class AbstractRemoteAgentService extends Disposable { _serviceBrand: any; @@ -83,7 +83,7 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon constructor( remoteAuthority: string, private readonly _commit: string | undefined, - private readonly _webSocketFactory: IWebSocketFactory, + private readonly _socketFactory: ISocketFactory, private readonly _environmentService: IEnvironmentService, private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, private readonly _signService: ISignService @@ -113,7 +113,7 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon const options: IConnectionOptions = { isBuilt: this._environmentService.isBuilt, commit: this._commit, - webSocketFactory: this._webSocketFactory, + socketFactory: this._socketFactory, addressProvider: { getAddress: async () => { if (firstCall) { @@ -121,8 +121,8 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon } else { this._onReconnecting.fire(undefined); } - const { host, port } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority); - return { host, port }; + const { authority } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority); + return { host: authority.host, port: authority.port }; } }, signService: this._signService diff --git a/src/vs/workbench/services/remote/common/remoteAgentService.ts b/src/vs/workbench/services/remote/common/remoteAgentService.ts index 6fd204af018..bc4d49641e1 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentService.ts @@ -8,7 +8,7 @@ import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platfo import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService'; import { Event } from 'vs/base/common/event'; -import { PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; +import { PersistenConnectionEvent as PersistentConnectionEvent, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; export const RemoteExtensionLogFileName = 'remoteagent'; @@ -17,6 +17,8 @@ export const IRemoteAgentService = createDecorator('remoteA export interface IRemoteAgentService { _serviceBrand: any; + readonly socketFactory: ISocketFactory; + getConnection(): IRemoteAgentConnection | null; getEnvironment(bail?: boolean): Promise; getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise; @@ -27,7 +29,7 @@ export interface IRemoteAgentConnection { readonly remoteAuthority: string; readonly onReconnecting: Event; - readonly onDidStateChange: Event; + readonly onDidStateChange: Event; getChannel(channelName: string): T; registerChannel>(channelName: string, channel: T): void; diff --git a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts index d101f0c57dc..538fb1be860 100644 --- a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts @@ -5,14 +5,17 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import product from 'vs/platform/product/node/product'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; import { ISignService } from 'vs/platform/sign/common/sign'; +import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; -export class RemoteAgentService extends AbstractRemoteAgentService { +export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService { + + public readonly socketFactory: ISocketFactory; private readonly _connection: IRemoteAgentConnection | null = null; @@ -22,8 +25,9 @@ export class RemoteAgentService extends AbstractRemoteAgentService { @ISignService signService: ISignService ) { super(environmentService); + this.socketFactory = nodeSocketFactory; if (remoteAuthority) { - this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeWebSocketFactory, environmentService, remoteAuthorityResolverService, signService)); + this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeSocketFactory, environmentService, remoteAuthorityResolverService, signService)); } } diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts index b8e30ea867b..9a359e44c28 100644 --- a/src/vs/workbench/services/remote/node/tunnelService.ts +++ b/src/vs/workbench/services/remote/node/tunnelService.ts @@ -12,7 +12,7 @@ import product from 'vs/platform/product/node/product'; import { connectRemoteAgentTunnel, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise { @@ -102,11 +102,11 @@ export class TunnelService implements ITunnelService { const options: IConnectionOptions = { isBuilt: this.environmentService.isBuilt, commit: product.commit, - webSocketFactory: nodeWebSocketFactory, + socketFactory: nodeSocketFactory, addressProvider: { getAddress: async () => { - const { host, port } = await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority); - return { host, port }; + const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority); + return { host: authority.host, port: authority.port }; } }, signService: this.signService diff --git a/src/vs/workbench/services/request/browser/requestService.ts b/src/vs/workbench/services/request/browser/requestService.ts new file mode 100644 index 00000000000..dca97347c35 --- /dev/null +++ b/src/vs/workbench/services/request/browser/requestService.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ILogService } from 'vs/platform/log/common/log'; +import { RequestChannelClient } from 'vs/platform/request/common/requestIpc'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { RequestService as BrowserRequestService } from 'vs/platform/request/browser/requestService'; + +export class RequestService extends BrowserRequestService { + + private readonly remoteRequestChannel: RequestChannelClient | null; + + constructor( + private readonly requestHandler: ((options: IRequestOptions) => Promise) | undefined, + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + @IConfigurationService configurationService: IConfigurationService, + @ILogService logService: ILogService + ) { + super(configurationService, logService); + const connection = remoteAgentService.getConnection(); + this.remoteRequestChannel = connection ? new RequestChannelClient(connection.getChannel('request')) : null; + } + + async request(options: IRequestOptions, token: CancellationToken): Promise { + if (this.requestHandler) { + return this.requestHandler(options); + } + try { + const context = await super.request(options, token); + if (this.remoteRequestChannel && context.res.statusCode === 405) { + return this.remoteRequestChannel.request(options, token); + } + return context; + } catch (error) { + if (this.remoteRequestChannel) { + const result = await this.remoteRequestChannel.request(options, token); + return result; + } + throw error; + } + } + +} \ No newline at end of file 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 00000000000..652aaf3a2de --- /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 MIT License. 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); + } + + flush(): Promise { + if (this._aiClient) { + return new Promise(resolve => { + this._aiClient!.flush(); + this._aiClient = undefined; + resolve(undefined); + }); + } + + return Promise.resolve(); + } +} + +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 5583a243cb2..6eaaf220ce5 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/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index a18d7c6592d..e262d28e73d 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -18,7 +18,8 @@ import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/to import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileService } from 'vs/platform/files/common/files'; import { ILogService } from 'vs/platform/log/common/log'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ITMSyntaxExtensionPoint, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; @@ -50,7 +51,8 @@ export abstract class AbstractTextMateService extends Disposable implements ITex @IFileService protected readonly _fileService: IFileService, @INotificationService private readonly _notificationService: INotificationService, @ILogService private readonly _logService: ILogService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IStorageService private readonly _storageService: IStorageService ) { super(); this._styleElement = dom.createStyleSheet(); @@ -221,7 +223,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex this._onDidEncounterLanguage.fire(languageId); } }); - return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService); + return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService, this._storageService); }, e => { onUnexpectedError(e); return null; @@ -332,6 +334,8 @@ export abstract class AbstractTextMateService extends Disposable implements ITex protected abstract _loadOnigLib(): Promise | undefined; } +const donotAskUpdateKey = 'editor.maxTokenizationLineLength.donotask'; + class TMTokenizationSupport implements ITokenizationSupport { private readonly _languageId: LanguageId; private readonly _actual: TMTokenization; @@ -342,11 +346,12 @@ class TMTokenizationSupport implements ITokenizationSupport { languageId: LanguageId, actual: TMTokenization, @INotificationService private readonly _notificationService: INotificationService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IStorageService private readonly _storageService: IStorageService ) { this._languageId = languageId; this._actual = actual; - this._tokenizationWarningAlreadyShown = false; + this._tokenizationWarningAlreadyShown = !!(this._storageService.getBoolean(donotAskUpdateKey, StorageScope.GLOBAL)); this._maxTokenizationLineLength = this._configurationService.getValue('editor.maxTokenizationLineLength'); this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('editor.maxTokenizationLineLength')) { @@ -372,7 +377,15 @@ class TMTokenizationSupport implements ITokenizationSupport { if (line.length >= this._maxTokenizationLineLength) { if (!this._tokenizationWarningAlreadyShown) { this._tokenizationWarningAlreadyShown = true; - this._notificationService.warn(nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. The length of a long line can be configured via `editor.maxTokenizationLineLength`.")); + this._notificationService.prompt( + Severity.Warning, + nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. The length of a long line can be configured via `editor.maxTokenizationLineLength`."), + [{ + label: nls.localize('neverAgain', "Don't Show Again"), + isSecondary: true, + run: () => this._storageService.store(donotAskUpdateKey, true, StorageScope.GLOBAL) + }] + ); } console.log(`Line (${line.substr(0, 15)}...): longer than ${this._maxTokenizationLineLength} characters, tokenization skipped.`); return nullTokenize2(this._languageId, line, state, offsetDelta); diff --git a/src/vs/workbench/services/textMate/browser/textMateService.ts b/src/vs/workbench/services/textMate/browser/textMateService.ts index 0e95d04a847..37e0f97252f 100644 --- a/src/vs/workbench/services/textMate/browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/browser/textMateService.ts @@ -14,6 +14,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IStorageService } from 'vs/platform/storage/common/storage'; export class TextMateService extends AbstractTextMateService { @@ -23,9 +24,10 @@ export class TextMateService extends AbstractTextMateService { @IFileService fileService: IFileService, @INotificationService notificationService: INotificationService, @ILogService logService: ILogService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService ) { - super(modeService, themeService, fileService, notificationService, logService, configurationService); + super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); } protected _loadVSCodeTextmate(): Promise { diff --git a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts index 21dd28d86fa..c794805b917 100644 --- a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts @@ -23,6 +23,7 @@ import { UriComponents, URI } from 'vs/base/common/uri'; import { MultilineTokensBuilder } from 'vs/editor/common/model/tokensStore'; import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents'; +import { IStorageService } from 'vs/platform/storage/common/storage'; const RUN_TEXTMATE_IN_WORKER = true; @@ -145,9 +146,10 @@ export class TextMateService extends AbstractTextMateService { @INotificationService notificationService: INotificationService, @ILogService logService: ILogService, @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService, @IModelService private readonly _modelService: IModelService, ) { - super(modeService, themeService, fileService, notificationService, logService, configurationService); + super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); this._worker = null; this._workerProxy = null; this._tokenizers = Object.create(null); @@ -246,4 +248,4 @@ export class TextMateService extends AbstractTextMateService { } } -registerSingleton(ITextMateService, TextMateService); \ No newline at end of file +registerSingleton(ITextMateService, TextMateService); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 5efed77064a..819e2a1fc08 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -24,7 +24,6 @@ import { RunOnceScheduler, timeout } from 'vs/base/common/async'; import { ITextBufferFactory } from 'vs/editor/common/model'; import { hash } from 'vs/base/common/hash'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { isLinux } from 'vs/base/common/platform'; import { toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/common/resources'; @@ -71,10 +70,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil static setSaveParticipant(handler: ISaveParticipant | null): void { TextFileEditorModel.saveParticipant = handler; } private readonly _onDidContentChange: Emitter = this._register(new Emitter()); - get onDidContentChange(): Event { return this._onDidContentChange.event; } + readonly onDidContentChange: Event = this._onDidContentChange.event; private readonly _onDidStateChange: Emitter = this._register(new Emitter()); - get onDidStateChange(): Event { return this._onDidStateChange.event; } + readonly onDidStateChange: Event = this._onDidStateChange.event; private resource: URI; @@ -781,17 +780,17 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Check for global settings file - if (isEqual(this.resource, this.environmentService.settingsResource, !isLinux)) { + if (isEqual(this.resource, this.environmentService.settingsResource)) { return 'global-settings'; } // Check for keybindings file - if (isEqual(this.resource, this.environmentService.keybindingsResource, !isLinux)) { + if (isEqual(this.resource, this.environmentService.keybindingsResource)) { return 'keybindings'; } // Check for locale file - if (isEqual(this.resource, joinPath(this.environmentService.userRoamingDataHome, 'locale.json'), !isLinux)) { + if (isEqual(this.resource, joinPath(this.environmentService.userRoamingDataHome, 'locale.json'))) { return 'locale'; } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index af67898ef69..8afe2d46768 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -15,28 +15,28 @@ import { ResourceMap } from 'vs/base/common/map'; export class TextFileEditorModelManager extends Disposable implements ITextFileEditorModelManager { private readonly _onModelDisposed: Emitter = this._register(new Emitter()); - get onModelDisposed(): Event { return this._onModelDisposed.event; } + readonly onModelDisposed: Event = this._onModelDisposed.event; private readonly _onModelContentChanged: Emitter = this._register(new Emitter()); - get onModelContentChanged(): Event { return this._onModelContentChanged.event; } + readonly onModelContentChanged: Event = this._onModelContentChanged.event; private readonly _onModelDirty: Emitter = this._register(new Emitter()); - get onModelDirty(): Event { return this._onModelDirty.event; } + readonly onModelDirty: Event = this._onModelDirty.event; private readonly _onModelSaveError: Emitter = this._register(new Emitter()); - get onModelSaveError(): Event { return this._onModelSaveError.event; } + readonly onModelSaveError: Event = this._onModelSaveError.event; private readonly _onModelSaved: Emitter = this._register(new Emitter()); - get onModelSaved(): Event { return this._onModelSaved.event; } + readonly onModelSaved: Event = this._onModelSaved.event; private readonly _onModelReverted: Emitter = this._register(new Emitter()); - get onModelReverted(): Event { return this._onModelReverted.event; } + readonly onModelReverted: Event = this._onModelReverted.event; private readonly _onModelEncodingChanged: Emitter = this._register(new Emitter()); - get onModelEncodingChanged(): Event { return this._onModelEncodingChanged.event; } + readonly onModelEncodingChanged: Event = this._onModelEncodingChanged.event; private readonly _onModelOrphanedChanged: Emitter = this._register(new Emitter()); - get onModelOrphanedChanged(): Event { return this._onModelOrphanedChanged.event; } + readonly onModelOrphanedChanged: Event = this._onModelOrphanedChanged.event; private _onModelsDirtyEvent: Event; private _onModelsSaveError: Event; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 14cdc03b5d2..33870009b83 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -31,7 +31,6 @@ import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { isEqualOrParent, isEqual, joinPath, dirname, extname, basename, toLocalResource } from 'vs/base/common/resources'; -import { posix } from 'vs/base/common/path'; import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -50,13 +49,13 @@ export abstract class TextFileService extends Disposable implements ITextFileSer _serviceBrand: ServiceIdentifier; private readonly _onAutoSaveConfigurationChange: Emitter = this._register(new Emitter()); - get onAutoSaveConfigurationChange(): Event { return this._onAutoSaveConfigurationChange.event; } + readonly onAutoSaveConfigurationChange: Event = this._onAutoSaveConfigurationChange.event; private readonly _onFilesAssociationChange: Emitter = this._register(new Emitter()); - get onFilesAssociationChange(): Event { return this._onFilesAssociationChange.event; } + readonly onFilesAssociationChange: Event = this._onFilesAssociationChange.event; private readonly _onWillMove = this._register(new Emitter()); - get onWillMove(): Event { return this._onWillMove.event; } + readonly onWillMove: Event = this._onWillMove.event; private _models: TextFileEditorModelManager; get models(): ITextFileEditorModelManager { return this._models; } @@ -436,7 +435,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer } async delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise { - const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource, !platform.isLinux /* ignorecase */)); + const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource)); await this.revertAll(dirtyFiles, { soft: true }); @@ -467,7 +466,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer } // Handle dirty source models if existing (if source URI is a folder, this can be multiple) - const dirtySourceModels = this.getDirtyFileModels().filter(model => isEqualOrParent(model.getResource(), source, !platform.isLinux /* ignorecase */)); + const dirtySourceModels = this.getDirtyFileModels().filter(model => isEqualOrParent(model.getResource(), source)); const dirtyTargetModelUris: URI[] = []; if (dirtySourceModels.length) { await Promise.all(dirtySourceModels.map(async sourceModel => { @@ -475,7 +474,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer let targetModelResource: URI; // If the source is the actual model, just use target as new resource - if (isEqual(sourceModelResource, source, !platform.isLinux /* ignorecase */)) { + if (isEqual(sourceModelResource, source)) { targetModelResource = target; } @@ -538,7 +537,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer async confirmSave(resources?: URI[]): Promise { if (this.environmentService.isExtensionDevelopment) { - return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assum we run interactive (e.g. tests) + return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) } const resourcesToConfirm = this.getDirty(resources); @@ -904,7 +903,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return joinPath(lastActiveFolder, untitledFileName); } - return schemeFilter === Schemas.file ? URI.file(untitledFileName) : URI.from({ scheme: schemeFilter, authority: remoteAuthority, path: posix.sep + untitledFileName }); + return untitledResource.with({ path: untitledFileName }); } async revert(resource: URI, options?: IRevertOptions): Promise { diff --git a/src/vs/workbench/services/textfile/node/textFileService.ts b/src/vs/workbench/services/textfile/node/textFileService.ts index 91fbdc6232e..3db51b4e10f 100644 --- a/src/vs/workbench/services/textfile/node/textFileService.ts +++ b/src/vs/workbench/services/textfile/node/textFileService.ts @@ -13,7 +13,7 @@ import { IFileStatWithMetadata, ICreateFileOptions, FileOperationError, FileOper import { Schemas } from 'vs/base/common/network'; import { exists, stat, chmod, rimraf, MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/base/node/pfs'; import { join, dirname } from 'vs/base/common/path'; -import { isMacintosh, isLinux } from 'vs/base/common/platform'; +import { isMacintosh } from 'vs/base/common/platform'; import product from 'vs/platform/product/node/product'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -490,7 +490,7 @@ export class EncodingOracle extends Disposable implements IResourceEncodings { for (const override of this.encodingOverrides) { // check if the resource is child of encoding override path - if (override.parent && isEqualOrParent(resource, override.parent, !isLinux /* ignorecase */)) { + if (override.parent && isEqualOrParent(resource, override.parent)) { return override.encoding; } diff --git a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts index 8d4e1a407d1..586639b4e8e 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts @@ -18,11 +18,11 @@ import { Schemas } from 'vs/base/common/network'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { rimraf, RimRafMode, copy, readFile, exists } from 'vs/base/node/pfs'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { tmpdir } from 'os'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { generateUuid } from 'vs/base/common/uuid'; import { join, basename } from 'vs/base/common/path'; import { getPathFromAmdModule } from 'vs/base/common/amd'; diff --git a/src/vs/workbench/services/themes/common/colorThemeStore.ts b/src/vs/workbench/services/themes/common/colorThemeStore.ts index a803474e606..272338755fc 100644 --- a/src/vs/workbench/services/themes/common/colorThemeStore.ts +++ b/src/vs/workbench/services/themes/common/colorThemeStore.ts @@ -53,17 +53,15 @@ export interface ColorThemeChangeEvent { export class ColorThemeStore { private extensionsColorThemes: ColorThemeData[]; - private readonly onDidChangeEmitter: Emitter; - public get onDidChange(): Event { return this.onDidChangeEmitter.event; } + private readonly onDidChangeEmitter = new Emitter(); + public readonly onDidChange: Event = this.onDidChangeEmitter.event; constructor(@IExtensionService private readonly extensionService: IExtensionService, defaultTheme: ColorThemeData) { this.extensionsColorThemes = [defaultTheme]; - this.onDidChangeEmitter = new Emitter(); this.initialize(); } - private initialize() { themesExtPoint.setHandler((extensions, delta) => { const previousIds: { [key: string]: boolean } = {}; diff --git a/src/vs/workbench/services/untitled/common/untitledEditorService.ts b/src/vs/workbench/services/untitled/common/untitledEditorService.ts index 5996ee18648..ad0498407ff 100644 --- a/src/vs/workbench/services/untitled/common/untitledEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledEditorService.ts @@ -118,16 +118,16 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor private mapResourceToAssociatedFilePath = new ResourceMap(); private readonly _onDidChangeContent: Emitter = this._register(new Emitter()); - get onDidChangeContent(): Event { return this._onDidChangeContent.event; } + readonly onDidChangeContent: Event = this._onDidChangeContent.event; private readonly _onDidChangeDirty: Emitter = this._register(new Emitter()); - get onDidChangeDirty(): Event { return this._onDidChangeDirty.event; } + readonly onDidChangeDirty: Event = this._onDidChangeDirty.event; private readonly _onDidChangeEncoding: Emitter = this._register(new Emitter()); - get onDidChangeEncoding(): Event { return this._onDidChangeEncoding.event; } + readonly onDidChangeEncoding: Event = this._onDidChangeEncoding.event; private readonly _onDidDisposeModel: Emitter = this._register(new Emitter()); - get onDidDisposeModel(): Event { return this._onDidDisposeModel.event; } + readonly onDidDisposeModel: Event = this._onDidDisposeModel.event; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, diff --git a/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts b/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts index 9693eaa5e00..ffed9c53d53 100644 --- a/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts +++ b/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts @@ -4,48 +4,229 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { IUserDataProvider, FileChangeEvent } from 'vs/workbench/services/userData/common/userData'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { FileChangeType } from 'vs/platform/files/common/files'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import * as resources from 'vs/base/common/resources'; +import { FileChangeType, IFileSystemProvider, FileType, IWatchOptions, IStat, FileSystemProviderErrorCode, FileSystemProviderError, FileWriteOptions, IFileChange, FileDeleteOptions, FileSystemProviderCapabilities, FileOverwriteOptions } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; -export class InMemoryUserDataProvider extends Disposable implements IUserDataProvider { - _serviceBrand: any; +class File implements IStat { - private _onDidChangeFile: Emitter = this._register(new Emitter()); - readonly onDidChangeFile: Event = this._onDidChangeFile.event; + type: FileType; + ctime: number; + mtime: number; + size: number; - private readonly store: Map = new Map(); + name: string; + data?: Uint8Array; - constructor() { - super(); - this._register(toDisposable(() => this.store.clear())); + constructor(name: string) { + this.type = FileType.File; + this.ctime = Date.now(); + this.mtime = Date.now(); + this.size = 0; + this.name = name; + } +} + +class Directory implements IStat { + + type: FileType; + ctime: number; + mtime: number; + size: number; + + name: string; + entries: Map; + + constructor(name: string) { + this.type = FileType.Directory; + this.ctime = Date.now(); + this.mtime = Date.now(); + this.size = 0; + this.name = name; + this.entries = new Map(); + } +} + +export type Entry = File | Directory; + +export class InMemoryUserDataProvider extends Disposable implements IFileSystemProvider { + + readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite; + readonly onDidChangeCapabilities: Event = Event.None; + + root = new Directory(''); + + // --- manage file metadata + + async stat(resource: URI): Promise { + return this._lookup(resource, false); } - async listFiles(path: string): Promise { - return []; - } - - async readFile(path: string): Promise { - if (this.store.has(path)) { - return VSBuffer.fromString(this.store.get(path)!).buffer; + async readdir(resource: URI): Promise<[string, FileType][]> { + const entry = this._lookupAsDirectory(resource, false); + let result: [string, FileType][] = []; + for (const [name, child] of entry.entries) { + result.push([name, child.type]); } - throw new Error(`Not Found: ${path}`); + return result; } - async writeFile(path: string, value: Uint8Array): Promise { - const exists = this.store.has(path); - const content = VSBuffer.wrap(value).toString(); - if (!exists || content !== this.store.get(path)) { - this.store.set(path, content); - this._onDidChangeFile.fire([{ path, type: exists ? FileChangeType.UPDATED : FileChangeType.ADDED }]); + // --- manage file contents + + async readFile(resource: URI): Promise { + const data = this._lookupAsFile(resource, false).data; + if (data) { + return data; } + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); } - async deleteFile(path: string): Promise { - if (this.store.has(path)) { - this.store.delete(path); - this._onDidChangeFile.fire([{ path, type: FileChangeType.DELETED }]); + async writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { + let basename = resources.basename(resource); + let parent = this._lookupParentDirectory(resource); + let entry = parent.entries.get(basename); + if (entry instanceof Directory) { + throw new FileSystemProviderError('file is directory', FileSystemProviderErrorCode.FileIsADirectory); } + if (!entry && !opts.create) { + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } + if (entry && opts.create && !opts.overwrite) { + throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists); + } + if (!entry) { + entry = new File(basename); + parent.entries.set(basename, entry); + this._fireSoon({ type: FileChangeType.ADDED, resource }); + } + entry.mtime = Date.now(); + entry.size = content.byteLength; + entry.data = content; + + this._fireSoon({ type: FileChangeType.UPDATED, resource }); + } + + // --- manage files/folders + + async rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise { + if (!opts.overwrite && this._lookup(to, true)) { + throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists); + } + + let entry = this._lookup(from, false); + let oldParent = this._lookupParentDirectory(from); + + let newParent = this._lookupParentDirectory(to); + let newName = resources.basename(to); + + oldParent.entries.delete(entry.name); + entry.name = newName; + newParent.entries.set(newName, entry); + + this._fireSoon( + { type: FileChangeType.DELETED, resource: from }, + { type: FileChangeType.ADDED, resource: to } + ); + } + + async delete(resource: URI, opts: FileDeleteOptions): Promise { + let dirname = resources.dirname(resource); + let basename = resources.basename(resource); + let parent = this._lookupAsDirectory(dirname, false); + if (!parent.entries.has(basename)) { + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } + parent.entries.delete(basename); + parent.mtime = Date.now(); + parent.size -= 1; + this._fireSoon({ type: FileChangeType.UPDATED, resource: dirname }, { resource, type: FileChangeType.DELETED }); + } + + async mkdir(resource: URI): Promise { + let basename = resources.basename(resource); + let dirname = resources.dirname(resource); + let parent = this._lookupAsDirectory(dirname, false); + + let entry = new Directory(basename); + parent.entries.set(entry.name, entry); + parent.mtime = Date.now(); + parent.size += 1; + this._fireSoon({ type: FileChangeType.UPDATED, resource: dirname }, { type: FileChangeType.ADDED, resource }); + } + + // --- lookup + + private _lookup(uri: URI, silent: false): Entry; + private _lookup(uri: URI, silent: boolean): Entry | undefined; + private _lookup(uri: URI, silent: boolean): Entry | undefined { + let parts = uri.path.split('/'); + let entry: Entry = this.root; + for (const part of parts) { + if (!part) { + continue; + } + let child: Entry | undefined; + if (entry instanceof Directory) { + child = entry.entries.get(part); + } + if (!child) { + if (!silent) { + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } else { + return undefined; + } + } + entry = child; + } + return entry; + } + + private _lookupAsDirectory(uri: URI, silent: boolean): Directory { + let entry = this._lookup(uri, silent); + if (entry instanceof Directory) { + return entry; + } + throw new FileSystemProviderError('file not a directory', FileSystemProviderErrorCode.FileNotADirectory); + } + + private _lookupAsFile(uri: URI, silent: boolean): File { + let entry = this._lookup(uri, silent); + if (entry instanceof File) { + return entry; + } + throw new FileSystemProviderError('file is a directory', FileSystemProviderErrorCode.FileIsADirectory); + } + + private _lookupParentDirectory(uri: URI): Directory { + const dirname = resources.dirname(uri); + return this._lookupAsDirectory(dirname, false); + } + + // --- manage file events + + private readonly _onDidChangeFile: Emitter = this._register(new Emitter()); + readonly onDidChangeFile: Event = this._onDidChangeFile.event; + + private _bufferedChanges: IFileChange[] = []; + private _fireSoonHandle?: NodeJS.Timer; + + + watch(resource: URI, opts: IWatchOptions): IDisposable { + // ignore, fires for all changes... + return Disposable.None; + } + + private _fireSoon(...changes: IFileChange[]): void { + this._bufferedChanges.push(...changes); + + if (this._fireSoonHandle) { + clearTimeout(this._fireSoonHandle); + } + + this._fireSoonHandle = setTimeout(() => { + this._onDidChangeFile.fire(this._bufferedChanges); + this._bufferedChanges.length = 0; + }, 5); } } \ No newline at end of file diff --git a/src/vs/workbench/services/userData/common/userData.ts b/src/vs/workbench/services/userData/common/userData.ts deleted file mode 100644 index 6ce93879fc3..00000000000 --- a/src/vs/workbench/services/userData/common/userData.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event } from 'vs/base/common/event'; -import { FileChangeType } from 'vs/platform/files/common/files'; - -/** - * The event user data providers must use to signal a file change. - */ -export interface FileChangeEvent { - - /** - * The type of change. - */ - readonly type: FileChangeType; - - /** - * The path of the file that has changed. - */ - readonly path: string; -} - -/** - * The userDataProvider is used to handle user specific application - * state like settings, keybindings, UI state (e.g. opened editors) and snippets. - * - * The API reflects a simple file system provider that comes with the notion of paths - * (UNIX slash separated) as well as files. Folders are not a top level concept (e.g. we - * do not require to create or delete them), however, files can be grouped beneath one path - * and also listed from that path. - * - * Example: - * ```ts - * await writeFile('snippets/global/markdown.json', ); - * await writeFile('snippets/global/html.json', ); - * await writeFile('snippets/global/javascript.json', ); - * - * const files = await listFiles('snippets/global'); - * console.log(files); // -> ['snippets/global/markdown.json', 'snippets/global/html.json', 'snippets/global/javascript.json'] - * ``` - */ -export interface IUserDataProvider { - - /** - * An event to signal that a file has been created, changed, or deleted. - */ - readonly onDidChangeFile: Event; - - /** - * Read the file contents of the given path. - * - * Throw an error if the path does not exist. - */ - readFile(path: string): Promise; - - /** - * Writes the provided content to the file path overwriting any existing content on that path. - * - * If the path does not exist, it will be created. - * - * Throw an error if the path is a parent to existing files. - */ - writeFile(path: string, content: Uint8Array): Promise; - - /** - * Delete the file at the given path. - * - * Does NOT throw an error when the path does not exist. - */ - deleteFile(path: string): Promise; - - /** - * Returns an array of files at the given path. - * - * Throw an error if the path does not exist or points to a file. - */ - listFiles(path: string): Promise; -} diff --git a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts index a99adf8ee1e..b8ba819bba8 100644 --- a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts +++ b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts @@ -9,14 +9,14 @@ import * as path from 'vs/base/common/path'; import * as uuid from 'vs/base/common/uuid'; import * as pfs from 'vs/base/node/pfs'; import { IFileService, FileChangeType, IFileChange, IFileSystemProviderWithFileReadWriteCapability, IStat, FileType, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; import { joinPath, dirname } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/electron-browser/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { BACKUPS } from 'vs/platform/environment/common/environment'; import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -230,7 +230,7 @@ suite('FileUserDataProvider', () => { test('delete existing file under folder', async () => { await pfs.mkdirp(path.join(userDataPath, 'snippets')); - pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); await testObject.del(joinPath(userDataResource, 'snippets/settings.json')); const exists = await pfs.exists(path.join(userDataPath, 'snippets', 'settings.json')); assert.equal(exists, false); @@ -238,7 +238,7 @@ suite('FileUserDataProvider', () => { test('resolve folder', async () => { await pfs.mkdirp(path.join(userDataPath, 'snippets')); - pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); const result = await testObject.resolve(joinPath(userDataResource, 'snippets')); assert.ok(result.isDirectory); assert.ok(result.children !== undefined); diff --git a/src/vs/workbench/test/browser/part.test.ts b/src/vs/workbench/test/browser/part.test.ts index 73878b4e603..ed151b3aced 100644 --- a/src/vs/workbench/test/browser/part.test.ts +++ b/src/vs/workbench/test/browser/part.test.ts @@ -10,7 +10,6 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService import { append, $, hide } from 'vs/base/browser/dom'; import { TestStorageService, TestLayoutService } from 'vs/workbench/test/workbenchTestServices'; import { StorageScope } from 'vs/platform/storage/common/storage'; -import { Orientation } from 'vs/base/browser/ui/grid/grid'; class SimplePart extends Part { @@ -19,7 +18,7 @@ class SimplePart extends Part { minimumHeight: number; maximumHeight: number; - layout(width: number, height: number, orientation: Orientation): void { + layout(width: number, height: number): void { throw new Error('Method not implemented.'); } @@ -172,4 +171,4 @@ suite('Workbench parts', () => { assert(!document.getElementById('myPart.title')); assert(document.getElementById('myPart.content')); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index c1ab20f2573..5b5fa096f9d 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -127,7 +127,7 @@ suite('Workbench base editor', () => { let oldEditorsCnt = EditorRegistry.getEditors().length; let oldInputCnt = (EditorRegistry).getEditorInputs().length; - EditorRegistry.registerEditor(d1, new SyncDescriptor(MyInput)); + EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyInput)]); EditorRegistry.registerEditor(d2, [new SyncDescriptor(MyInput), new SyncDescriptor(MyOtherInput)]); assert.equal(EditorRegistry.getEditors().length, oldEditorsCnt + 2); @@ -148,8 +148,8 @@ suite('Workbench base editor', () => { let oldEditors = EditorRegistry.getEditors(); (EditorRegistry).setEditors([]); - EditorRegistry.registerEditor(d2, new SyncDescriptor(ResourceEditorInput)); - EditorRegistry.registerEditor(d1, new SyncDescriptor(MyResourceInput)); + EditorRegistry.registerEditor(d2, [new SyncDescriptor(ResourceEditorInput)]); + EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyResourceInput)]); let inst = new TestInstantiationService(); @@ -168,7 +168,7 @@ suite('Workbench base editor', () => { let oldEditors = EditorRegistry.getEditors(); (EditorRegistry).setEditors([]); - EditorRegistry.registerEditor(d1, new SyncDescriptor(ResourceEditorInput)); + EditorRegistry.registerEditor(d1, [new SyncDescriptor(ResourceEditorInput)]); let inst = new TestInstantiationService(); diff --git a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts index 556d88a5512..991bfbede8a 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -26,6 +26,7 @@ const emptyDialogService = new class implements IDialogService { const emptyCommandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand: (commandId: string, ...args: any[]): Promise => { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index e1edb23fe4c..76040fc8eae 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -573,18 +573,18 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert.equal(includePattern, 'foo'); - assert.equal(_includeFolder, undefined); - assert.equal(excludePatternOrDisregardExcludes, undefined); + assert.equal(_includeFolder, null); + assert.equal(excludePatternOrDisregardExcludes, null); assert.equal(maxResults, 10); - return Promise.resolve(undefined); + return Promise.resolve(null); } }); const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); - return ws.findFiles('foo', undefined!, 10, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -595,17 +595,17 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert.equal(includePattern, 'glob/**'); assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); - assert.equal(excludePatternOrDisregardExcludes, undefined); - return Promise.resolve(undefined); + assert.equal(excludePatternOrDisregardExcludes, null); + return Promise.resolve(null); } }); const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); - return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined!, 10, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined, 10, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -616,12 +616,12 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert.equal(includePattern, 'glob/**'); assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); assert.equal(excludePatternOrDisregardExcludes, false); - return Promise.resolve(undefined); + return Promise.resolve(null); } }); @@ -637,9 +637,9 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; - return Promise.resolve(undefined); + return Promise.resolve(null); } }); @@ -657,10 +657,10 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651 - return Promise.resolve(undefined); + return Promise.resolve(null); } }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts index 07ee0ca6290..50f8a7aa045 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts @@ -39,7 +39,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('foo', undefined, undefined, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('foo', null, null, 10, new CancellationTokenSource().token); }); test('exclude defaults', () => { @@ -61,7 +61,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, undefined, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, null, 10, new CancellationTokenSource().token); }); test('disregard excludes', () => { @@ -82,7 +82,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, false, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, false, 10, new CancellationTokenSource().token); }); test('exclude string', () => { @@ -96,6 +96,6 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, 'exclude/**', 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, 'exclude/**', 10, new CancellationTokenSource().token); }); }); diff --git a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts index 40eb17f7d9a..c61f19b0d58 100644 --- a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts +++ b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts @@ -12,12 +12,15 @@ import { debugExceptionWidgetBackground } from 'vs/workbench/contrib/debug/brows import { debugToolBarBackground } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { buttonBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePage'; import { embeddedEditorBackground } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart'; -import { request, asText } from 'vs/base/node/request'; +import { asText } from 'vs/platform/request/common/request'; import * as pfs from 'vs/base/node/pfs'; import * as path from 'vs/base/common/path'; import * as assert from 'assert'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { RequestService } from 'vs/platform/request/node/requestService'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { NullLogService } from 'vs/platform/log/common/log'; interface ColorInfo { @@ -40,7 +43,7 @@ export const experimental: string[] = []; // 'settings.modifiedItemForeground', suite('Color Registry', function () { test('all colors documented', async function () { - const reqContext = await request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' }, CancellationToken.None); + const reqContext = await new RequestService(new TestConfigurationService(), new NullLogService()).request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' }, CancellationToken.None); const content = (await asText(reqContext))!; const expression = /\-\s*\`([\w\.]+)\`: (.*)/g; diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 3a383fb6cc7..48ebaf8e296 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -474,6 +474,10 @@ export class TestLayoutService implements IWorkbenchLayoutService { return true; } + getDimension(_part: Parts): Dimension { + return new Dimension(0, 0); + } + public getContainer(_part: Parts): HTMLElement { return null!; } @@ -667,7 +671,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { whenRestored: Promise = Promise.resolve(undefined); willRestoreEditors = false; - dimension = { width: 800, height: 600 }; + contentDimension = { width: 800, height: 600 }; get activeGroup(): IEditorGroup { return this.groups[0]; @@ -703,11 +707,11 @@ export class TestEditorGroupsService implements IEditorGroupsService { throw new Error('not implemented'); } - getSize(_group: number | IEditorGroup): number { - return 100; + getSize(_group: number | IEditorGroup): { width: number, height: number } { + return { width: 100, height: 100 }; } - setSize(_group: number | IEditorGroup, _size: number): void { } + setSize(_group: number | IEditorGroup, _size: { width: number, height: number }): void { } arrangeGroups(_arrangement: GroupsArrangement): void { } @@ -1473,7 +1477,7 @@ export class TestWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - log(_severity: string, ..._messages: string[]): Promise { + log(_severity: string, _args: string[]): Promise { return Promise.resolve(); } @@ -1595,30 +1599,6 @@ export class TestSharedProcessService implements ISharedProcessService { registerChannel(channelName: string, channel: any): void { } } -export class NullFileSystemProvider implements IFileSystemProvider { - - capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly; - - onDidChangeCapabilities: Event = Event.None; - onDidChangeFile: Event = Event.None; - - constructor(private disposableFactory: () => IDisposable = () => Disposable.None) { } - - watch(resource: URI, opts: IWatchOptions): IDisposable { return this.disposableFactory(); } - stat(resource: URI): Promise { return Promise.resolve(undefined!); } - mkdir(resource: URI): Promise { return Promise.resolve(undefined!); } - readdir(resource: URI): Promise<[string, FileType][]> { return Promise.resolve(undefined!); } - delete(resource: URI, opts: FileDeleteOptions): Promise { return Promise.resolve(undefined!); } - rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise { return Promise.resolve(undefined!); } - copy?(from: URI, to: URI, opts: FileOverwriteOptions): Promise { return Promise.resolve(undefined!); } - readFile?(resource: URI): Promise { return Promise.resolve(undefined!); } - writeFile?(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { return Promise.resolve(undefined!); } - open?(resource: URI, opts: FileOpenOptions): Promise { return Promise.resolve(undefined!); } - close?(fd: number): Promise { return Promise.resolve(undefined!); } - read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return Promise.resolve(undefined!); } - write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return Promise.resolve(undefined!); } -} - export class RemoteFileSystemProvider implements IFileSystemProvider { constructor(private readonly diskFileSystemProvider: IFileSystemProvider, private readonly remoteAuthority: string) { } @@ -1646,4 +1626,4 @@ export class RemoteFileSystemProvider implements IFileSystemProvider { write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return this.diskFileSystemProvider.write!(fd, pos, data, offset, length); } private toFileResource(resource: URI): URI { return resource.with({ scheme: Schemas.file, authority: '' }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index dc3e95c613d..ba1ea7a2075 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -53,7 +53,7 @@ import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDeco import { IMarkerService } from 'vs/platform/markers/common/markers'; import { MarkerService } from 'vs/platform/markers/common/markerService'; import { IDownloadService } from 'vs/platform/download/common/download'; -import { DownloadService } from 'vs/platform/download/node/downloadService'; +import { DownloadService } from 'vs/platform/download/common/downloadService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; @@ -64,12 +64,12 @@ 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/node/extensionGalleryService'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { RequestService } from 'vs/platform/request/browser/requestService'; import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; @@ -124,12 +124,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'; @@ -137,8 +136,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); @@ -167,6 +167,7 @@ registerSingleton(IMenubarService, MenubarService); registerSingleton(IURLService, RelayURLService); registerSingleton(ITunnelService, TunnelService, true); registerSingleton(ICredentialsService, KeytarCredentialsService, true); +registerSingleton(IWorkspaceStatsService, WorkspaceStatsService, true); //#endregion @@ -200,7 +201,7 @@ import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; import 'vs/workbench/contrib/preferences/browser/preferences.contribution'; import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences'; -import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch'; +import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/browser/preferencesSearch'; registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); // Logs @@ -255,9 +256,10 @@ 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/electron-browser/extensionsViewlet'; +import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; // Output Panel import 'vs/workbench/contrib/output/browser/output.contribution'; @@ -343,5 +345,6 @@ import 'vs/workbench/contrib/experiments/electron-browser/experiments.contributi // Issues import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; +import { IWorkspaceStatsService, WorkspaceStatsService } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService'; //#endregion diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index e0b3b1ed9ad..d411ccd3280 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -6,7 +6,9 @@ import 'vs/workbench/workbench.web.main'; import { main } from 'vs/workbench/browser/web.main'; import { UriComponents } from 'vs/base/common/uri'; -import { IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability } from 'vs/platform/files/common/files'; +import { IFileSystemProvider } from 'vs/platform/files/common/files'; +import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; export interface IWorkbenchConstructionOptions { @@ -36,7 +38,18 @@ export interface IWorkbenchConstructionOptions { * Experimental: The userDataProvider is used to handle user specific application * state like settings, keybindings, UI state (e.g. opened editors) and snippets. */ - userDataProvider?: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability; + userDataProvider?: IFileSystemProvider; + + /** + * Experimental: Optional request handler to handle http requests. + * In case not provided, workbench uses XMLHttpRequest. + */ + requestHandler?: (requestOptions: IRequestOptions) => Promise; + + /** + * A factory for web sockets. + */ + webSocketFactory?: IWebSocketFactory; } /** diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index f417d5c967d..4d5cf7bfbf9 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -51,10 +51,10 @@ import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecora import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { MarkerService } from 'vs/platform/markers/common/markerService'; -// import { IDownloadService } from 'vs/platform/download/common/download'; -// import { DownloadService } from 'vs/platform/download/node/downloadService'; -// import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -// import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; +import { IDownloadService } from 'vs/platform/download/common/download'; +import { DownloadService } from 'vs/platform/download/common/downloadService'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -63,11 +63,9 @@ 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/node/extensionGalleryService'; -// import { IRequestService } from 'vs/platform/request/node/request'; -// import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -75,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'; @@ -122,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); @@ -148,15 +145,14 @@ registerSingleton(IOpenerService, OpenerService, true); registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl); registerSingleton(IMarkerDecorationsService, MarkerDecorationsService); registerSingleton(IMarkerService, MarkerService, true); -// registerSingleton(IDownloadService, DownloadService, true); -// registerSingleton(IClipboardService, ClipboardService, true); +registerSingleton(IDownloadService, DownloadService, true); +registerSingleton(IClipboardService, BrowserClipboardService, true); registerSingleton(IContextKeyService, ContextKeyService); registerSingleton(IModelService, ModelServiceImpl, true); registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService); registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); registerSingleton(IContextViewService, ContextViewService, true); -// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); -// registerSingleton(IRequestService, RequestService, true); +registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); registerSingleton(ILifecycleService, BrowserLifecycleService); // registerSingleton(ILocalizationsService, LocalizationsService); // registerSingleton(ISharedProcessService, SharedProcessService, true); @@ -265,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/electron-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/test/all.js b/test/all.js index 350e8606800..834d63250bb 100644 --- a/test/all.js +++ b/test/all.js @@ -6,16 +6,12 @@ /*eslint-env mocha*/ /*global define,run*/ -var assert = require('assert'); -var path = require('path'); -var glob = require('glob'); -var istanbul = require('istanbul'); -var i_remap = require('remap-istanbul/lib/remap'); -var jsdom = require('jsdom-no-contextify'); -var minimatch = require('minimatch'); -var fs = require('fs'); -var vm = require('vm'); -var TEST_GLOB = '**/test/**/*.test.js'; +const assert = require('assert'); +const path = require('path'); +const glob = require('glob'); +const jsdom = require('jsdom-no-contextify'); +const TEST_GLOB = '**/test/**/*.test.js'; +const coverage = require('./coverage'); var optimist = require('optimist') .usage('Run the Code tests. All mocha options apply.') @@ -23,7 +19,6 @@ var optimist = require('optimist') .describe('run', 'Run a single file').string('run') .describe('coverage', 'Generate a coverage report').boolean('coverage') .describe('only-monaco-editor', 'Run only monaco editor tests').boolean('only-monaco-editor') - .describe('forceLoad', 'Force loading').boolean('forceLoad') .describe('browser', 'Run tests in a browser').boolean('browser') .alias('h', 'help').boolean('h') .describe('h', 'Show help'); @@ -58,103 +53,13 @@ function main() { }; if (argv.coverage) { - var instrumenter = new istanbul.Instrumenter(); - - var seenSources = {}; - - loaderConfig.nodeInstrumenter = function (contents, source) { - seenSources[source] = true; - - if (minimatch(source, TEST_GLOB)) { - return contents; - } - - return instrumenter.instrumentSync(contents, source); - }; + coverage.initialize(loaderConfig); process.on('exit', function (code) { if (code !== 0) { return; } - - if (argv.forceLoad) { - var allFiles = glob.sync(out + '/vs/**/*.js'); - allFiles = allFiles.map(function (source) { - return path.join(__dirname, '..', source); - }); - allFiles = allFiles.filter(function (source) { - if (seenSources[source]) { - return false; - } - if (minimatch(source, TEST_GLOB)) { - return false; - } - if (/fixtures/.test(source)) { - return false; - } - return true; - }); - allFiles.forEach(function (source, index) { - var contents = fs.readFileSync(source).toString(); - contents = instrumenter.instrumentSync(contents, source); - var stopAt = contents.indexOf('}\n__cov'); - stopAt = contents.indexOf('}\n__cov', stopAt + 1); - - var str = '(function() {' + contents.substr(0, stopAt + 1) + '});'; - var r = vm.runInThisContext(str, source); - r.call(global); - }); - } - - let remapIgnores = /\b((marked)|(raw\.marked)|(nls)|(css))\.js$/; - - var remappedCoverage = i_remap(global.__coverage__, { exclude: remapIgnores }).getFinalCoverage(); - - // The remapped coverage comes out with broken paths - var toUpperDriveLetter = function (str) { - if (/^[a-z]:/.test(str)) { - return str.charAt(0).toUpperCase() + str.substr(1); - } - return str; - }; - var toLowerDriveLetter = function (str) { - if (/^[A-Z]:/.test(str)) { - return str.charAt(0).toLowerCase() + str.substr(1); - } - return str; - }; - - var REPO_PATH = toUpperDriveLetter(path.join(__dirname, '..')); - var fixPath = function (brokenPath) { - var startIndex = brokenPath.indexOf(REPO_PATH); - if (startIndex === -1) { - return toLowerDriveLetter(brokenPath); - } - return toLowerDriveLetter(brokenPath.substr(startIndex)); - }; - - var finalCoverage = {}; - for (var entryKey in remappedCoverage) { - var entry = remappedCoverage[entryKey]; - entry.path = fixPath(entry.path); - finalCoverage[fixPath(entryKey)] = entry; - } - - var collector = new istanbul.Collector(); - collector.add(finalCoverage); - - var coveragePath = path.join(path.dirname(__dirname), '.build', 'coverage'); - var reportTypes = []; - if (argv.run || argv.runGlob) { - // single file running - coveragePath += '-single'; - reportTypes = ['lcovonly']; - } else { - reportTypes = ['json', 'lcov', 'html']; - } - var reporter = new istanbul.Reporter(null, coveragePath); - reporter.addAll(reportTypes); - reporter.write(collector, true, function () { }); + coverage.createReport(argv.run || argv.runGlob); }); } diff --git a/test/coverage.js b/test/coverage.js new file mode 100644 index 00000000000..bf7e7aa3f95 --- /dev/null +++ b/test/coverage.js @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const minimatch = require('minimatch'); +const fs = require('fs'); +const path = require('path'); +const iLibInstrument = require('istanbul-lib-instrument'); +const iLibCoverage = require('istanbul-lib-coverage'); +const iLibSourceMaps = require('istanbul-lib-source-maps'); +const iLibReport = require('istanbul-lib-report'); +const iReports = require('istanbul-reports'); + +const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '..')); + +exports.initialize = function (loaderConfig) { + const instrumenter = iLibInstrument.createInstrumenter(); + loaderConfig.nodeInstrumenter = function (contents, source) { + if (minimatch(source, '**/test/**/*.test.js')) { + // tests don't get instrumented + return contents; + } + // Try to find a .map file + let map = null; + try { + map = JSON.parse(fs.readFileSync(`${source}.map`).toString()); + } catch (err) { + // missing source map... + } + return instrumenter.instrumentSync(contents, source, map); + }; +}; + +exports.createReport = function (isSingle) { + const mapStore = iLibSourceMaps.createSourceMapStore(); + const coverageMap = iLibCoverage.createCoverageMap(global.__coverage__); + const transformed = mapStore.transformCoverage(coverageMap); + + // Paths come out all broken + let newData = Object.create(null); + Object.keys(transformed.map.data).forEach((file) => { + const entry = transformed.map.data[file]; + const fixedPath = fixPath(entry.path); + entry.data.path = fixedPath; + newData[fixedPath] = entry; + }); + transformed.map.data = newData; + + const tree = iLibReport.summarizers.flat(transformed.map); + const context = iLibReport.createContext({ + dir: path.join(__dirname, `../.build/coverage${isSingle ? '-single' : ''}`) + }); + + let reports = []; + if (isSingle) { + reports.push(iReports.create('lcovonly')); + } else { + reports.push(iReports.create('json')); + reports.push(iReports.create('lcov')); + reports.push(iReports.create('html')); + } + reports.forEach(report => tree.visit(report, context)); +}; + +function toUpperDriveLetter(str) { + if (/^[a-z]:/.test(str)) { + return str.charAt(0).toUpperCase() + str.substr(1); + } + return str; +} + +function toLowerDriveLetter(str) { + if (/^[A-Z]:/.test(str)) { + return str.charAt(0).toLowerCase() + str.substr(1); + } + return str; +} + +function fixPath(brokenPath) { + const startIndex = brokenPath.lastIndexOf(REPO_PATH); + if (startIndex === -1) { + return toLowerDriveLetter(brokenPath); + } + return toLowerDriveLetter(brokenPath.substr(startIndex)); +} diff --git a/test/electron/renderer.html b/test/electron/renderer.html index 1eb67318bfa..72454389597 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -19,4 +19,4 @@ - \ No newline at end of file + diff --git a/test/electron/renderer.js b/test/electron/renderer.js index 4d5a7f0f1ee..36668cd53b3 100644 --- a/test/electron/renderer.js +++ b/test/electron/renderer.js @@ -9,11 +9,9 @@ const { ipcRenderer } = require('electron'); const assert = require('assert'); const path = require('path'); const glob = require('glob'); -const minimatch = require('minimatch'); -const istanbul = require('istanbul'); -const i_remap = require('remap-istanbul/lib/remap'); const util = require('util'); const bootstrap = require('../../src/bootstrap'); +const coverage = require('../coverage'); // Disabled custom inspect. See #38847 if (util.inspect && util.inspect['defaultOptions']) { @@ -42,77 +40,19 @@ function initLoader(opts) { } }; - // nodeInstrumenter when coverage is requested if (opts.coverage) { - const instrumenter = new istanbul.Instrumenter(); - - loaderConfig.nodeInstrumenter = function (contents, source) { - return minimatch(source, _tests_glob) - ? contents // don't instrument tests itself - : instrumenter.instrumentSync(contents, source); - }; + // initialize coverage if requested + coverage.initialize(loaderConfig); } loader.require.config(loaderConfig); } function createCoverageReport(opts) { - return new Promise(resolve => { - - if (!opts.coverage) { - return resolve(undefined); - } - - const exclude = /\b((marked)|(raw\.marked)|(nls)|(css))\.js$/; - const remappedCoverage = i_remap(global.__coverage__, { exclude: exclude }).getFinalCoverage(); - - // The remapped coverage comes out with broken paths - function toUpperDriveLetter(str) { - if (/^[a-z]:/.test(str)) { - return str.charAt(0).toUpperCase() + str.substr(1); - } - return str; - } - function toLowerDriveLetter(str) { - if (/^[A-Z]:/.test(str)) { - return str.charAt(0).toLowerCase() + str.substr(1); - } - return str; - } - - const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '../..')); - const fixPath = function (brokenPath) { - const startIndex = brokenPath.indexOf(REPO_PATH); - if (startIndex === -1) { - return toLowerDriveLetter(brokenPath); - } - return toLowerDriveLetter(brokenPath.substr(startIndex)); - }; - - const finalCoverage = Object.create(null); - for (const entryKey in remappedCoverage) { - const entry = remappedCoverage[entryKey]; - entry.path = fixPath(entry.path); - finalCoverage[fixPath(entryKey)] = entry; - } - - const collector = new istanbul.Collector(); - collector.add(finalCoverage); - - let coveragePath = path.join(path.dirname(__dirname), '../.build/coverage'); - let reportTypes = []; - if (opts.run || opts.runGlob) { - // single file running - coveragePath += '-single'; - reportTypes = ['lcovonly']; - } else { - reportTypes = ['json', 'lcov', 'html']; - } - - const reporter = new istanbul.Reporter(null, coveragePath); - reporter.addAll(reportTypes); - reporter.write(collector, true, resolve); - }); + if (opts.coverage) { + coverage.createReport(opts.run || opts.runGlob); + } + return Promise.resolve(undefined); } function loadTestModules(opts) { diff --git a/test/smoke/package.json b/test/smoke/package.json index 80f93f04d89..11b5662b207 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -22,7 +22,7 @@ "@types/webdriverio": "4.6.1", "concurrently": "^3.5.1", "cpx": "^1.5.0", - "electron": "4.2.5", + "electron": "4.2.7", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^5.2.0", @@ -35,5 +35,8 @@ "tmp": "0.0.33", "typescript": "2.9.2", "watch": "^1.0.2" + }, + "dependencies": { + "vscode-uri": "^2.0.3" } } diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 21a0fe252a1..eefa5d35838 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -156,7 +156,12 @@ async function setupRepository(): Promise { console.log('*** Copying test project repository:', opts['test-repo']); rimraf.sync(workspacePath); // not platform friendly - cp.execSync(`cp -R "${opts['test-repo']}" "${workspacePath}"`); + if (process.platform === 'win32') { + cp.execSync(`xcopy /E "${opts['test-repo']}" "${workspacePath}"\\*`); + } else { + cp.execSync(`cp -R "${opts['test-repo']}" "${workspacePath}"`); + } + } else { if (!fs.existsSync(workspacePath)) { console.log('*** Cloning test project repository...'); diff --git a/test/smoke/src/vscode/code.ts b/test/smoke/src/vscode/code.ts index 0b9c739cb69..9f468fddd8b 100644 --- a/test/smoke/src/vscode/code.ts +++ b/test/smoke/src/vscode/code.ts @@ -12,6 +12,7 @@ import { tmpName } from 'tmp'; import { IDriver, connect as connectDriver, IDisposable, IElement, Thenable } from './driver'; import { Logger } from '../logger'; import { ncp } from 'ncp'; +import { URI } from 'vscode-uri'; const repoPath = path.join(__dirname, '../../../..'); @@ -128,11 +129,8 @@ export async function spawn(options: SpawnOptions): Promise { if (options.remote) { // Replace workspace path with URI - args.shift(); - args.push( - `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri`, - `vscode-remote://test+test${options.workspacePath}`, - ); + args[0] = `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(options.workspacePath).path}`; + if (codePath) { // running against a build: copy the test resolver extension const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver'); diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index ca28dd6bf19..b86356d3ac3 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -676,10 +676,10 @@ electron-download@^4.1.0: semver "^5.4.1" sumchecker "^2.0.2" -electron@4.2.5: - version "4.2.5" - resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.5.tgz#1d1432c38e2b2190318f7ca30897cdfdcf942e5a" - integrity sha512-P132MXzTtyn2ZaekhKi5JeHzmTAMuR/uQt4hrg3vfJV7fpncx9SL6UFwHAK1DU13iiyZJqqIziNUu+o8nODHsA== +electron@4.2.7: + version "4.2.7" + resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.7.tgz#bdd2dbf489a4a4255405bd8330cc8509831d29ba" + integrity sha512-Azpkw0OPzKVipSsN9/0DrBQhXOpG48Q1gTG7Akchtv37s8TijMe403TUgHxGGhw2ti117ek51kYf7NXLhjXqoA== dependencies: "@types/node" "^10.12.18" electron-download "^4.1.0" @@ -2623,6 +2623,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== + watch@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" diff --git a/test/splitview/package.json b/test/splitview/package.json new file mode 100644 index 00000000000..d6ce0c37374 --- /dev/null +++ b/test/splitview/package.json @@ -0,0 +1,13 @@ +{ + "name": "splitview", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "devDependencies": { + "koa": "^2.5.1", + "koa-mount": "^3.0.0", + "koa-route": "^3.2.0", + "koa-static": "^5.0.0", + "mz": "^2.7.0" + } +} \ No newline at end of file diff --git a/test/splitview/public/index.html b/test/splitview/public/index.html new file mode 100644 index 00000000000..602682d6aab --- /dev/null +++ b/test/splitview/public/index.html @@ -0,0 +1,138 @@ + + + + + Splitview + + + + +
+
+ + + + + + \ No newline at end of file diff --git a/test/splitview/server.js b/test/splitview/server.js new file mode 100644 index 00000000000..67f25363671 --- /dev/null +++ b/test/splitview/server.js @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const fs = require('mz/fs'); +const path = require('path'); +const Koa = require('koa'); +const _ = require('koa-route'); +const serve = require('koa-static'); +const mount = require('koa-mount'); + +const app = new Koa(); + +app.use(serve('public')); +app.use(mount('/static', serve('../../out'))); + +app.listen(3000); +console.log('http://localhost:3000'); \ No newline at end of file diff --git a/test/splitview/yarn.lock b/test/splitview/yarn.lock new file mode 100644 index 00000000000..237201a684e --- /dev/null +++ b/test/splitview/yarn.lock @@ -0,0 +1,341 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +accepts@^1.2.2: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +any-promise@^1.0.0, any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +content-disposition@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookies@~0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" + integrity sha1-fIphX1SBxhq58WyDNzG8uPZjuZs= + dependencies: + depd "~1.1.1" + keygrip "~1.0.2" + +debug@*, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^2.6.1: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@^1.1.0, depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +error-inject@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= + +escape-html@~1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +fresh@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +http-assert@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" + integrity sha1-oxpc+IyHPsu1eWkH1NbxMujAHko= + dependencies: + deep-equal "~1.0.1" + http-errors "~1.6.1" + +http-errors@^1.2.8, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +is-generator-function@^1.0.3: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +keygrip@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91" + integrity sha1-rTKXxVcGneqLz+ek+kkbdcXd65E= + +koa-compose@^3.0.0, koa-compose@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= + dependencies: + any-promise "^1.1.0" + +koa-compose@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= + +koa-mount@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" + integrity sha1-CMqzuD0xRC7Yt+dcVLGr65IuwZc= + dependencies: + debug "^2.6.1" + koa-compose "^3.2.1" + +koa-route@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/koa-route/-/koa-route-3.2.0.tgz#76298b99a6bcfa9e38cab6fe5c79a8733e758bce" + integrity sha1-dimLmaa8+p44yrb+XHmocz51i84= + dependencies: + debug "*" + methods "~1.1.0" + path-to-regexp "^1.2.0" + +koa-send@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" + integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ== + dependencies: + debug "^3.1.0" + http-errors "^1.6.3" + mz "^2.7.0" + resolve-path "^1.4.0" + +koa-static@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" + integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ== + dependencies: + debug "^3.1.0" + koa-send "^5.0.0" + +koa@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.1.tgz#79f8b95f8d72d04fe9a58a8da5ebd6d341103f9c" + integrity sha512-cchwbMeG2dv3E2xTAmheDAuvR53tPgJZN/Hf1h7bTzJLSPcFZp8/t5+bNKJ6GaQZoydhZQ+1GNruhKdj3lIrug== + dependencies: + accepts "^1.2.2" + content-disposition "~0.5.0" + content-type "^1.0.0" + cookies "~0.7.0" + debug "*" + delegates "^1.0.0" + depd "^1.1.0" + destroy "^1.0.3" + error-inject "~1.0.0" + escape-html "~1.0.1" + fresh "^0.5.2" + http-assert "^1.1.0" + http-errors "^1.2.8" + is-generator-function "^1.0.3" + koa-compose "^4.0.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + mime-types "^2.0.7" + on-finished "^2.1.0" + only "0.0.2" + parseurl "^1.3.0" + statuses "^1.2.0" + type-is "^1.5.5" + vary "^1.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +methods@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@^2.0.7, mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +on-finished@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +only@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= + +parseurl@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +path-is-absolute@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-to-regexp@^1.2.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= + dependencies: + isarray "0.0.1" + +resolve-path@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" + integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= + dependencies: + http-errors "~1.6.2" + path-is-absolute "1.0.1" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +"statuses@>= 1.4.0 < 2", statuses@^1.2.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= + dependencies: + any-promise "^1.0.0" + +type-is@^1.5.5: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +vary@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= diff --git a/test/tree/public/compressed.json b/test/tree/public/compressed.json new file mode 100644 index 00000000000..c0b5d4d7161 --- /dev/null +++ b/test/tree/public/compressed.json @@ -0,0 +1,15620 @@ +[ + { + "element": { + "name": "eclipse.platform.debug" + }, + "children": [ + { + "element": { + "name": ".git" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + }, + { + "element": { + "name": "branches" + }, + "children": [] + }, + { + "element": { + "name": "config" + }, + "incompressible": true + }, + { + "element": { + "name": "description" + }, + "incompressible": true + }, + { + "element": { + "name": "hooks" + }, + "children": [ + { + "element": { + "name": "applypatch-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "commit-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "fsmonitor-watchman.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "post-update.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-applypatch.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-commit.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-push.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-rebase.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-receive.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "prepare-commit-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "update.sample" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "index" + }, + "incompressible": true + }, + { + "element": { + "name": "info" + }, + "children": [ + { + "element": { + "name": "exclude" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "logs" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + }, + { + "element": { + "name": "refs" + }, + "children": [ + { + "element": { + "name": "heads" + }, + "children": [ + { + "element": { + "name": "master" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "remotes" + }, + "children": [ + { + "element": { + "name": "origin" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "objects" + }, + "children": [ + { + "element": { + "name": "info" + }, + "children": [] + }, + { + "element": { + "name": "pack" + }, + "children": [ + { + "element": { + "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.idx" + }, + "incompressible": true + }, + { + "element": { + "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.pack" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "packed-refs" + }, + "incompressible": true + }, + { + "element": { + "name": "refs" + }, + "children": [ + { + "element": { + "name": "heads" + }, + "children": [ + { + "element": { + "name": "master" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "remotes" + }, + "children": [ + { + "element": { + "name": "origin" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "tags" + }, + "children": [ + { + "element": { + "name": "I20190722-1800" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "shallow" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": ".gitignore" + }, + "incompressible": true + }, + { + "element": { + "name": "CONTRIBUTING" + }, + "incompressible": true + }, + { + "element": { + "name": "LICENSE" + }, + "incompressible": true + }, + { + "element": { + "name": "NOTICE" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.externaltools" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "ExternalToolsCore.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "BackgroundResourceRefresher.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsCoreUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramLaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "BuilderCoreUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolBuilder.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "registry" + }, + "children": [ + { + "element": { + "name": "ExternalToolMigration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMigrationMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMigrationMessages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.core.variables" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "dynamicVariables.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "valueVariables.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ContributedValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DynamicVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EclipseHomeVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionEngine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesMessages.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "IDynamicVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDynamicVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStringVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStringVariableManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariableInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariableListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.core" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".options" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "DebugEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugException.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointManagerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEventFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEventSetListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationMigrationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationWorkingCopy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchMode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchesListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchesListener2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IProcessFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPrototypeAttributesLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Launch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "AbstractDebugCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugCommandRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDisconnectHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDropToFrameHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IEnabledStateRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRestartHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IResumeHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFiltersHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepIntoHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepOverHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepReturnHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITerminateHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "Breakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointImportParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDisconnect.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDropToFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IErrorReportingExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IFilteredStep.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IFlushableStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IIndexedValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDelegate2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureTypeDelegate2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockRetrieval.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockRetrievalExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableSourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRegister.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRegisterGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStep.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFilters.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamsProxy2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendResume.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITerminate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITriggerPoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueModification.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryByte.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RuntimeProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AbstractSourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableSourceLocator2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePathComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePathComputerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "containers" + }, + "children": [ + { + "element": { + "name": "AbstractSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSourceContainerTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArchiveSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompositeSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContainerSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LocalFileStorage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ZipEntryStorage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "BreakpointImportParticipantDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCoreMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCoreMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugOptions.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConfigurationElementConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionsListener2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalDebugCoreConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMementoConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InputStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationWorkingCopy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchMode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchablePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "NullStreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OutputStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Preferences.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PreferredDelegateModifyListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshScopeComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFilterManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPropertyResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "XMLMemento.java" + }, + "incompressible": true + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "CommandAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ForEachCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Request.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFiltersCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommand.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "groups" + }, + "children": [ + { + "element": { + "name": "GroupLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupMemberChangeListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "observer" + }, + "children": [ + { + "element": { + "name": "ProcessObserver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamObserver.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "SourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLocatorMementoComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourcePathComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "containers" + }, + "children": [ + { + "element": { + "name": "ArchiveSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainerType.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ContainerResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DateTimeResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceResolver.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "breakpointImportParticipants.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationComparators.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchDelegates.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchModes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "logicalStructureProviders.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "logicalStructureTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "processFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceContainerTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceLocators.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcePathComputers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "statusHandlers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "stepFilters.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "watchExpressionDelegates.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.core" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "pdavm" + }, + "children": [ + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "pdavm" + }, + "children": [ + { + "element": { + "name": "PDAVirtualMachine.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "tests" + }, + "children": [ + { + "element": { + "name": "vmtest10.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest2.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest3.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest6.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest8.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest9.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest_children.pda" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "readme.html" + }, + "incompressible": true + }, + { + "element": { + "name": "samples" + }, + "children": [ + { + "element": { + "name": "counter.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "drop.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "example.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "fibonacci.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "registers.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "stack.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "structures.pda" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "build.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "midi" + }, + "children": [ + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "ClockControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LengthControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TempoControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TimeControl.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pda" + }, + "children": [ + { + "element": { + "name": "DebugCorePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "PDALineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunToLineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAWatchpoint.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "PDALaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "IPDAEventListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAArray.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAArrayEntry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordStructureDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "protocol" + }, + "children": [ + { + "element": { + "name": "PDABitFieldData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAChildrenCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAClearBreakpointCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDACommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDACommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADropFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvalCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvalResultEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEventStopCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAExitedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAGroupsCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAListResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDANoSuchLabelEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAPopDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAPushDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegisterData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARestartCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAResumedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunControlEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetBreakpointCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetVarCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackDepthCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackDepthCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStartedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStepCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStepReturnCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASuspendedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATerminateCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATerminatedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAUnimplementedInstructionEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMResumedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMStartedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMSuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMSuspendedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMTerminatedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVarCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAWatchCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "PDASourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourcePathComputerDelegate.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "src_ant" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "ant" + }, + "children": [ + { + "element": { + "name": "tasks" + }, + "children": [ + { + "element": { + "name": "PreProcessor.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.memory" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "hex_tree.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "launch.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_segment.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_unit.gif" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "MemoryViewSamplePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleDebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleRegister.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleRegisterGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "messages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "engine" + }, + "children": [ + { + "element": { + "name": "SampleEngine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleMemoryUnit.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launchconfig" + }, + "children": [ + { + "element": { + "name": "SampleLaunchConfigurationDelegateEx.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleLaunchTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleModelPresentation.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.mixedmode" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "mixedmode" + }, + "children": [ + { + "element": { + "name": "Activator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AntExtraTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClearPreferredDelegatesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DoNothingLaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DoNothingMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "messages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.ui" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "pop.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "push.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "pop.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "push.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "clef.png" + }, + "incompressible": true + }, + { + "element": { + "name": "note.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "pda.gif" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "midi" + }, + "children": [ + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "CheckboxModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlsMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiEventLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiEventModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiStepOverHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerColumnFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerControlsModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackColumnFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackModelProxy.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "detailpanes" + }, + "children": [ + { + "element": { + "name": "ClockSliderDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TempoSliderDetailPane.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "ExampleLaunchStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiTabGroup.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pda" + }, + "children": [ + { + "element": { + "name": "DebugUIPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "AdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddPDAMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommandAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTargetContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTargetProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARestartDebugCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAThreadEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAViewActionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVirtualFindAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "PDABreakpointAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditorAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunToLineAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAToggleWatchpointsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAToggleWatchpointsTargetFactory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "editor" + }, + "children": [ + { + "element": { + "name": "AnnotationHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAContentAssistProcessor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAContentAssistant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditorMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAScanner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourceViewerConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopFrameActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordFinder.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "PDALaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATabGroup.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "presentation" + }, + "children": [ + { + "element": { + "name": "PDAModelPresentation.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "views" + }, + "children": [ + { + "element": { + "name": "AbstractDataStackViewHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CanPushTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CheckboxView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DataStackView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PushHandler.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.tests" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "Platform Debug Test Suite.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "image1.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "image2.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "tests" + }, + "children": [ + { + "element": { + "name": "AbstractDebugTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AutomatedSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LocalSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerformanceSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestsPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint" + }, + "children": [ + { + "element": { + "name": "BreakpointOrderingTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleDocumentAdapterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleTestUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MockProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamsProxyTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expressions" + }, + "children": [ + { + "element": { + "name": "ExpressionManagerTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launching" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AcceleratorSubstitutionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArgumentParsingTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArgumentsPrinter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CancellingLaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugFileStore.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugFileSystem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchFavoriteTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchHistoryTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshTabTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestLaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "SourceLookupFacilityTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestSourceDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestSourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestStackFrame.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "statushandlers" + }, + "children": [ + { + "element": { + "name": "StatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StatusHandlerTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "stepfilters" + }, + "children": [ + { + "element": { + "name": "StepFiltersTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestStepFilter.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "view" + }, + "children": [ + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "DynamicRenderingBindings.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockDynamic.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockOne.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockThree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockTwo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingTypeDelegate.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "viewer" + }, + "children": [ + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "AbstractViewerModelTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CheckTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ColumnPresentationTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTransformTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITestModelUpdatesListenerConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerCheckTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerDeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerFilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerLazyTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerPerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerPopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerSelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerStateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerTopIndexTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LazyTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PresentationContextTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestModelUpdatesListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewerAutopopulateAgent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreePathWrapper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerDeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerFilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerLazyModeTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerPerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerPopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerSelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerStateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VisibleVirtualItemValidator.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "test-import" + }, + "children": [ + { + "element": { + "name": "Import1.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import2.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import3.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import4.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import5.launch" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "test.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.ui" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".options" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": ".api_filters" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "css" + }, + "children": [ + { + "element": { + "name": "e4-dark_debug_prefstyle.css" + }, + "incompressible": true + }, + { + "element": { + "name": "e4-light_debug_prefstyle.css" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "changevariablevalue_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "changevariablevalue_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.gif.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.gif@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_triggers.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dtool16" + }, + "children": [ + { + "element": { + "name": "debug_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dview16" + }, + "children": [ + { + "element": { + "name": "breakpoint_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "changevariablevalue_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "changevariablevalue_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_triggers.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "etool16" + }, + "children": [ + { + "element": { + "name": "debug_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "eview16" + }, + "children": [ + { + "element": { + "name": "breakpoint_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "arraypartition_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "arraypartition_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_type.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_type@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkpd_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkpd_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "check.png" + }, + "incompressible": true + }, + { + "element": { + "name": "check@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "common_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "common_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugts_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugts_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugtt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugtt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "envvar_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "envvar_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expression_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expression_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "file_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "file_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "fldr_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "fldr_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericreggroup_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericreggroup_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericregister_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericregister_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericvariable_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericvariable_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr_top.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr_top@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "jar_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "jar_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "ldebug_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "ldebug_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lgroup_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lgroup_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lrun_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lrun_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memorychanged_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memorychanged_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprc_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprc_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprct_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprct_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "persp_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "persp_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prj_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prj_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "proto_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "proto_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "refresh_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "refresh_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rundebug.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rundebug@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_running_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_running_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminatedlaunch_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminatedlaunch_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "thread_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "thread_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threads_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threads_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threadt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threadt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "uncheck.png" + }, + "incompressible": true + }, + { + "element": { + "name": "uncheck@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "workset.png" + }, + "incompressible": true + }, + { + "element": { + "name": "workset@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj_disabled@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ovr16" + }, + "children": [ + { + "element": { + "name": "error.png" + }, + "incompressible": true + }, + { + "element": { + "name": "error@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prototype.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prototype@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_breakpoint_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_breakpoint_ov@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stcksync_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stcksync_ov@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "transparent.png" + }, + "incompressible": true + }, + { + "element": { + "name": "transparent@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr_ov@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "wizban" + }, + "children": [ + { + "element": { + "name": "adddir_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "addsrcloc_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "editdir_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_wiz.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "breakpointOrganizers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consoleColorProviders.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consoleLineTrackers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "contextViewBindings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "debugModelContextBindings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "debugModelPresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "detailPaneFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTabGroups.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTabs.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTypeImages.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchGroups.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchShortcuts.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryRenderings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceContainerPresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "stringVariablePresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "toggleBreakpointsTargetFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "variableValueEditors.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "AbstractDebugCheckboxSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugListSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointImageProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildBeforeLaunchStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ColorManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompositeDebugImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModelPropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPerspectiveFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPluginImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DelegatingModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DynamicInstructionPointerAnnotation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalDebugUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchHistoryChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchLabelChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageDescriptorRegistry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerAnnotation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerImageProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LazyModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MultipleInputDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Pair.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceExtender.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SWTFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateToggleValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextGetSetEditingSupport.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableValueEditorManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingDirectoryStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractDebugActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractRemoveAllActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSelectionActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "AddToFavoritesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CollapseAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConfigureColumnsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExecutionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchablePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenDebugConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenProfileConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenRunConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllTerminatedAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetRunToLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StatusInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointsTargetManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleFilterAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewManagementAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpointGroups" + }, + "children": [ + { + "element": { + "name": "AbstractBreakpointsViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AdvancedGroupBreakpointsByAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointGroupMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointGroupMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointSelectionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClearDefaultBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyBreakpointsActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsByAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsByDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasteBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveFromWorkingSetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectBreakpointWorkingsetDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SetDefaultBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleDefaultGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetsAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpointSortBy" + }, + "children": [ + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SortBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SortBreakpointsByAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "AccessWatchpointToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsCollapseAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsExpandAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeleteWorkingsetsMessageDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisableBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnableBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkBreakpointsWithDebugViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ModificationWatchpointToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModifyWatchpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenBreakpointMarkerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllTriggerPointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetMethodBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetToggleBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetToggleLineBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetWatchpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerEnableDisableBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowSupportedBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowTargetBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SkipAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointObjectActionDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expressions" + }, + "children": [ + { + "element": { + "name": "AddWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConvertToWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyExpressionsToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisableWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditWatchExpressinInPlaceAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnableWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasteWatchExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ReevaluateWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionFactoryTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ChangeVariableValueAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChangeVariableValueInputDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllVariablesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowTypesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleDetailPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "details" + }, + "children": [ + { + "element": { + "name": "DetailPaneAssignValueAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneMaxLengthAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneMaxLengthDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneWordWrapAction.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "IBreakpointContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OtherBreakpointCategory.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionsUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugActionHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExecuteActionRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ICommandParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IEnabledTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAllActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRelaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRelaunchHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRemoveAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateActionsRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateHandlerRequest.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "contextlaunching" + }, + "children": [ + { + "element": { + "name": "ContextMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextRunner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchingResourceManager.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "contexts" + }, + "children": [ + { + "element": { + "name": "DebugContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextSourceProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModelContextBindingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugWindowContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchSuspendTrigger.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendTriggerAdapterFactory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elements" + }, + "children": [ + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "AsynchronousDebugLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultBreakpointsViewInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultVariableCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemorySegmentLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameSourceDisplayAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableColumnFactoryAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionCellModifier.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "groups" + }, + "children": [ + { + "element": { + "name": "CommonTabLite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupCycleHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupElementLaunchedHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsupportedModeHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "hover" + }, + "children": [ + { + "element": { + "name": "DebugTextHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionInformationControlCreator.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "importexport" + }, + "children": [ + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "BreakpointImportExport.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsPathDecorator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EmbeddedBreakpointsViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IImportExportConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportExportMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardExportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardExportBreakpointsPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpointsPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpointsSelectionPage.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launchconfigurations" + }, + "children": [ + { + "element": { + "name": "ExportLaunchConfigurationsWizard.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportLaunchConfigurationsWizardPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportLaunchConfigurationsWizard.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportLaunchConfigurationsWizardPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardMessages.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClosedProjectFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CollapseAllLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompileErrorProjectPromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompileErrorPromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateLaunchConfigurationPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModePromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeleteLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeletedProjectFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DuplicateLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DuplicateLaunchDelegatesStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FavoritesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterDropDownMenuCreator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchCategoryFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationEditDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationFilteredTree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationPresentationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationPropertiesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupWrapper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTreeContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTypeContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTypeFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegateContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegateNotAvailableHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchHistory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchTabContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OrganizeFavoritesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerspectiveManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetWithPrototypeValuesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SaveScopeResourcesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectFavoritesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLaunchModesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLaunchersDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowCommandLineDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnlinkPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetsFilter.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "IMemoryBlockConnection.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableDebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingBindings.java" + }, + "incompressible": true + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "AbstractAsyncTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractAsyncTextRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewPresentationContext.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "elements" + }, + "children": [ + { + "element": { + "name": "BreakpointContainerLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContainerMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerInputMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ThreadContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionEditor.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "preferences" + }, + "children": [ + { + "element": { + "name": "BooleanFieldEditor2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencesMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencesMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugPreferenceConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchPerspectivePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchersPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchingPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessPropertyPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunDebugPropertiesPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariablePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewManagementPreferencePage.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "quickaccess" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchQuickAccessElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunQuickAccessComputer.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AddContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BasicContainerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DownAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditSourceLookupPathAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LookupSourceAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Prompter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResolveDuplicatesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestoreDefaultAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupFacility.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupPanel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "browsers" + }, + "children": [ + { + "element": { + "name": "ArchiveFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArchiveSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainerBrowser.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "stringsubstitution" + }, + "children": [ + { + "element": { + "name": "FilePrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IArgumentSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasswordPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PromptingResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedResourceManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedResourceResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedTextResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariablePresentationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPropertyArgumentSelector.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "viewers" + }, + "children": [ + { + "element": { + "name": "AbstractUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousSchedulingRuleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousTableModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousTableViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FindElementDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelNode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PartPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableAddRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableEditorImpl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableInsertRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRemoveRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableReplaceRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breadcrumb" + }, + "children": [ + { + "element": { + "name": "AbstractBreadcrumb.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItemDetails.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItemDropDown.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreadcrumbDropDownSite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeViewerDropDown.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "ChildrenCountUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementCompareRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementMementoRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTransform.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HasChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InternalTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InternalVirtualTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MementoUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SubTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TimeTriggeredProgressMonitorDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerAdapterService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerStateTracker.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerUpdateMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualCopyToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualFindAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "ICheckUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ICheckboxModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenCountUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentation2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentationFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementCompareRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementMementoRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHasChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelDelta.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelDeltaVisitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxy2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxyFactory2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelSelectionPolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelSelectionPolicyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStateUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStatusMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewActionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputRequestor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualItemListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualItemValidator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelDelta.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewerFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualItem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualTree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualTreeModelViewer.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "AbstractColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAsynchronousContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAsynchronousLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IContainerRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelRequestMonitor.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "update" + }, + "children": [ + { + "element": { + "name": "BreakpointContainerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultExpressionModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultModelSelectionPolicyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSelectionPolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultVariableViewModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultWatchExpressionModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EventHandlerModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ThreadEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewEventHandler.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "views" + }, + "children": [ + { + "element": { + "name": "DebugModelPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIViewsMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIViewsMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugExceptionHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "BreakpointContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContainerWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointOrganizerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointOrganizerManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointPersistableElementAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointSetOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypeOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetCache.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetElementAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsDragAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsDropAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FileBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetCategory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleLineNotifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleRemoveAllTerminatedAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleRemoveLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleShowPreferencesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTerminateAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsolePageParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessTypePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowStandardErrorAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowStandardOutAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowWhenContentChangesAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expression" + }, + "children": [ + { + "element": { + "name": "ExpressionDropAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionView.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launch" + }, + "children": [ + { + "element": { + "name": "BreadcrumbDropDownAutoExpandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbWorkbenchPart.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementHelper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugToolBarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugViewModeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Decoration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DecorationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewBreadcrumb.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewCopyToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceNotFoundEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceNotFoundEditorInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StandardDecoration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRemoveHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "AbstractMemoryViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingContextAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CodePagesPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryViewTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkRenderingPanesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlocksTreeViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewIdRegistry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewPrefAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewSynchronizationService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTreeViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MonitorMemoryBlockDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "NewMemoryViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PinMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PropertyChangeNotifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveMemoryRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveRenderingContextAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetMemoryBlockPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetAddMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SetPaddedStringPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SwitchMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SynchronizeInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleMemoryMonitorsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleSplitPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleViewPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneOrientationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneRenderingMgr.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneSelectionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewTabEnablementManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "renderings" + }, + "children": [ + { + "element": { + "name": "ASCIIRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ASCIIRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractBaseTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTableRenderingLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractVirtualContentTableModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncCopyTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncPrintTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncVirtualContentTableViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BasicDebugViewContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BigEndianAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyTableRenderingToClipboardAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultEndianessAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ErrorRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FormatTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FormatTableRenderingDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressComposite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexIntegerRenderingDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IContentChangeComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPresentationErrorListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualContentListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LittleEndianAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemorySegment.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PendingPropertyChanges.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrintTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ReformatAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingsUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetToBaseAddressAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SignedIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SignedIntegerRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLabelProviderEx.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPrefAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPropertiesPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsignedIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsignedIntegerRenderingTypeDelegate.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "modules" + }, + "children": [ + { + "element": { + "name": "IHelpContextIdProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesViewMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "registers" + }, + "children": [ + { + "element": { + "name": "RegistersView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegistersViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegistersViewMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "AvailableLogicalStructuresAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditVariableLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IndexedValuePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IndexedVariablePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureCache.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectionDragAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleShowColumnsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableViewToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewResourceBundleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "details" + }, + "children": [ + { + "element": { + "name": "AbstractDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AvailableDetailPanesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneContainer2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageDetailPane.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "AbstractBreakpointOrganizerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchConfigurationTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypeCategory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPopup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUITools.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeferredDebugElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizerDelegateExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointTypeCategory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEditorPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelPresentationExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane3.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInstructionPointerPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTab2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchShortcut2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueDetailListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InspectPopupDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrototypeDecorator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrototypeTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingDirectoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchHistoryAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypesContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportBreakpointsOperation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAddMemoryBlocksTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAddMemoryRenderingsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRunToLineTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetExtension2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetManagerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVariableValueEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapter2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapterExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportBreakpointsOperation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenLaunchDialogAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerBreakpointTypesActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerEnableDisableBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerRunToLineActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerToggleBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleMethodBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleWatchpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleColorProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FileLink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleColorProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleHyperlink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleLineTracker.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleLineTrackerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "contexts" + }, + "children": [ + { + "element": { + "name": "AbstractDebugContextProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextProvider2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendTrigger.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendTriggerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "AbstractMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractMemoryRenderingBindingsProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTextRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockTablePresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingBindingsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingBindingsProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSite2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSynchronizationService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRepositionableMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IResettableMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AbstractSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonSourceNotFoundEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonSourceNotFoundEditorInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceDisplay.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "stringsubstitution" + }, + "children": [ + { + "element": { + "name": "IArgumentSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.ui.console" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "clcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "cview16" + }, + "children": [ + { + "element": { + "name": "console_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dview16" + }, + "children": [ + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "eview16" + }, + "children": [ + { + "element": { + "name": "console_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "consoleFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consolePageParticipants.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consolePatternMatchListeners.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "AbstractConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleDocumentPartitioner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsolePageParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHyperlink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHyperlink2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleInputStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleOutputStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPatternMatchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPatternMatchListenerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IScrollLockStateProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageConsoleStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsolePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsoleViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "ClearOutputAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CloseConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextViewerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextViewerGotoLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleDocument.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleDocumentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleDropDownAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleFactoryExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleHyperlinkPosition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePageParticipantExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePatternMatcher.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePluginImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleResourceBundleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleResourceBundleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTypePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleUIPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleViewConsoleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleWorkbenchPart.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FollowHyperlinkAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HyperlinkUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalConsoleConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePartitioner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchListenerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PinConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ScrollLockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamDecoder.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordWrapAction.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.ui.externaltools" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".gitignore" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": ".api_filters" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "External Tools Base" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "ExternalToolsBuildTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsBuilderTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsLaunchConfigurationMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsLaunchConfigurationMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IgnoreWhiteSpaceComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetComparator.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "menu" + }, + "children": [ + { + "element": { + "name": "ExternalToolMenuDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenExternalToolsConfigurations.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "BuilderUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolsHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPreferenceConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageDescriptorRegistry.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "BuilderLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuilderPropertyPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditCommandDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "FileSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeAndListGroup.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "BuildFilesResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildProjectResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildTypeResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPathResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMessages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "Program Tools Support" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "program" + }, + "children": [ + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "ExternalToolsProgramMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramBuilderTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramTabGroup.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dtool16" + }, + "children": [ + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "etool16" + }, + "children": [ + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "build_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "build_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "builder.png" + }, + "incompressible": true + }, + { + "element": { + "name": "builder@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "classpath.png" + }, + "incompressible": true + }, + { + "element": { + "name": "classpath@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "invalid_build_tool.png" + }, + "incompressible": true + }, + { + "element": { + "name": "invalid_build_tool@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "main_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "main_tab@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "wizban" + }, + "children": [ + { + "element": { + "name": "ext_tools_wiz.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "configurationDuplicationMaps.exsd" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + } + ] + } +] \ No newline at end of file diff --git a/test/tree/public/index.html b/test/tree/public/index.html index 7c83e9b045c..17c88461c4b 100644 --- a/test/tree/public/index.html +++ b/test/tree/public/index.html @@ -44,7 +44,7 @@ require.config({ baseUrl: '/static' }); - require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { + require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/compressedObjectTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { CompressedObjectTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { function createIndexTree(opts) { opts = opts || {}; @@ -100,6 +100,57 @@ return { tree, treeFilter }; } + function createCompressedObjectTree(opts) { + opts = opts || {}; + + const delegate = { + getHeight() { return 22; }, + getTemplateId() { return 'template'; }, + hasDynamicHeight() { return true; } + }; + + const renderer = { + templateId: 'template', + renderTemplate(container) { return container; }, + renderElement(element, index, container) { + if (element.element.elements.length > 1) { + container.innerHTML = `🙈 ${element.element.elements.map(el => el.name).join('/')}`; + } else { + container.innerHTML = element.element.elements[0].name; + } + }, + disposeElement() { }, + disposeTemplate() { } + }; + + const treeFilter = new class { + constructor() { + this.pattern = null; + let timeout; + filter.oninput = () => { + clearTimeout(timeout); + timeout = setTimeout(() => this.updatePattern(), 300); + }; + } + updatePattern() { + if (!filter.value) { + this.pattern = null; + } else { + this.pattern = new RegExp(filter.value, 'i'); + } + + perf('refilter', () => tree.refilter()); + } + filter(el) { + return (this.pattern ? this.pattern.test(el) : true) ? TreeVisibility.Visible : TreeVisibility.Recurse; + } + }; + + const tree = new CompressedObjectTree(container, delegate, [renderer], { ...opts, filter: treeFilter, setRowLineHeight: false, collapseByDefault: true, setRowLineHeight: true }); + + return { tree, treeFilter }; + } + function createAsyncDataTree() { const delegate = { getHeight() { return 22; }, @@ -155,7 +206,7 @@ getChildren(element) { return new Promise((c, e) => { const xhr = new XMLHttpRequest(); - xhr.open('GET', element ? `/api/readdir?path=${element.element.path}` : '/api/readdir'); + xhr.open('GET', element ? `/ api / readdir ? path = ${element.element.path} ` : '/api/readdir'); xhr.send(); xhr.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { @@ -258,7 +309,7 @@ const errors = []; for (let j = 1; j <= 3; j++) { - errors.push({ element: `error #${j}` }); + errors.push({ element: `error #${j} ` }); } files.push({ element: `file #${i}`, children: errors }); @@ -289,6 +340,23 @@ break; } + case '?compressed': { + const { tree, treeFilter } = createCompressedObjectTree(); + + expandall.onclick = () => perf('expand all', () => tree.expandAll()); + collapseall.onclick = () => perf('collapse all', () => tree.collapseAll()); + + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/compressed.json'); + xhr.send(); + xhr.onreadystatechange = function () { + if (this.readyState == 4 && this.status == 200) { + tree.setChildren(null, JSON.parse(this.responseText)); + } + }; + + break; + } case '?height': { const { tree, treeFilter } = createIndexTree({ supportDynamicHeights: true }); diff --git a/test/tree/tree.js b/test/tree/tree.js new file mode 100644 index 00000000000..4d5a9b5f271 --- /dev/null +++ b/test/tree/tree.js @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const path = require('path'); +const fs = require('fs'); + +function collect(location) { + const element = { name: path.basename(location) }; + const stat = fs.statSync(location); + + if (!stat.isDirectory()) { + return { element, incompressible: true }; + } + + const children = fs.readdirSync(location) + .map(child => path.join(location, child)) + .map(collect); + + return { element, children }; +} + +console.log(JSON.stringify(collect(process.cwd()))); \ No newline at end of file diff --git a/tslint.json b/tslint.json index 3ff7147730b..155bd9a4115 100644 --- a/tslint.json +++ b/tslint.json @@ -515,6 +515,13 @@ "**/vs/**" ] }, + { + "target": "**/vs/workbench/contrib/extensions/browser/**", + "restrictions": [ + "semver-umd", + "**/vs/**" + ] + }, { "target": "**/vs/code/node/**", "restrictions": [ @@ -563,7 +570,11 @@ ] }, { - "target": "**/{node,electron-browser,electron-main,extensions}/**", + "target": "**/{node,electron-browser,electron-main}/**", + "restrictions": "**/*" + }, + { + "target": "**/extensions/**", "restrictions": "**/*" }, { diff --git a/yarn.lock b/yarn.lock index f786bf95403..f1c162556e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,6 +14,40 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/generator@^7.4.0", "@babel/generator@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" + integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA== + dependencies: + "@babel/types" "^7.5.0" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -23,6 +57,44 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" + integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== + +"@babel/template@^7.1.0", "@babel/template@^7.4.0": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.4.3": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485" + integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.5.0" + "@babel/types" "^7.5.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" + integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@types/commander@^2.11.0": version "2.12.2" resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae" @@ -35,10 +107,10 @@ resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.0.tgz#a61ab476e5e628cd07a846330df53b85e05c8ce0" integrity sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw== -"@types/keytar@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/keytar/-/keytar-4.0.1.tgz#e2cf6405dc33861424e59b67516c66d2cf7bc21b" - integrity sha512-loKBID6UL4QjhD2scuvv6oAPlQ/WAY7aYTDyKlKo7fIgriLS8EZExqT567cHL5CY6si51MRoX1+r3mitD3eYrA== +"@types/keytar@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@types/keytar/-/keytar-4.4.0.tgz#ca24e6ee6d0df10c003aafe26e93113b8faf0d8e" + integrity sha512-cq/NkUUy6rpWD8n7PweNQQBpw2o0cf5v6fbkUVEpOB9VzzIvyPvSEId1/goIj+MciW2v1Lw5mRimKO01XgE9EA== "@types/minimist@^1.2.0": version "1.2.0" @@ -261,11 +333,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abbrev@1.0.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= - accepts@~1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" @@ -377,15 +444,6 @@ ajv@^6.5.3, ajv@^6.6.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -749,7 +807,7 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@1.x, async@^1.4.0, async@^1.5.2: +async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= @@ -991,7 +1049,7 @@ boom@5.x.x: dependencies: hoek "4.x.x" -brace-expansion@^1.0.0, brace-expansion@^1.1.7: +brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" integrity sha1-wHshHHyVLsH479Uad+8NHTmQopI= @@ -1232,11 +1290,6 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= - camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -1282,14 +1335,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - chainsaw@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" @@ -1487,15 +1532,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -1704,6 +1740,11 @@ commander@^2.19.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commandpost@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/commandpost/-/commandpost-1.2.1.tgz#2e9c4c7508b9dc704afefaa91cab92ee6054cc68" @@ -2108,14 +2149,14 @@ debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -2162,7 +2203,7 @@ deep-extend@~0.4.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8= -deep-is@~0.1.2, deep-is@~0.1.3: +deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -2421,14 +2462,6 @@ each-props@^1.3.0: is-plain-object "^2.0.1" object.defaults "^1.1.0" -eachr@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eachr/-/eachr-3.2.0.tgz#2c35e43ea086516f7997cf80b7aa64d55a4a4484" - integrity sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ= - dependencies: - editions "^1.1.1" - typechecker "^4.3.0" - ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -2446,11 +2479,6 @@ ecstatic@^3.0.0: minimist "^1.1.0" url-join "^2.0.5" -editions@^1.1.1, editions@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== - editorconfig@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.0.tgz#b6dd4a0b6b9e76ce48e066bdc15381aebb8804fd" @@ -2638,30 +2666,6 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@1.7.x: - version "1.7.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.7.1.tgz#30ecfcf66ca98dc67cd2fd162abeb6eafa8ce6fc" - integrity sha1-MOz89mypjcZ80v0WKr626vqM5vw= - dependencies: - esprima "^1.2.2" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.5.0" - optionalDependencies: - source-map "~0.2.0" - -escodegen@1.8.x: - version "1.8.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= - dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.2.0" - eslint-scope@^3.7.1: version "3.7.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" @@ -2791,21 +2795,11 @@ espree@^5.0.0: acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" -esprima@2.5.x: - version "2.5.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.5.0.tgz#f387a46fd344c1b1a39baf8c20bfb43b6d0058cc" - integrity sha1-84ekb9NEwbGjm6+MIL+0O20AWMw= - -esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: +esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= -esprima@^1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" - integrity sha1-CZNQL+r2aBODJXVvMPmlH+7sEek= - esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -2833,11 +2827,6 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= - estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -2950,10 +2939,10 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -expand-template@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.1.tgz#981f188c0c3a87d2e28f559bc541426ff94f21dd" - integrity sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg== +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" @@ -3078,15 +3067,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-opts@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-3.3.1.tgz#5abbedc98c0d5202e3278727f9192d7e086c6be1" - integrity sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E= - dependencies: - eachr "^3.2.0" - editions "^1.1.1" - typechecker "^4.3.0" - extract-zip@^1.6.5: version "1.6.6" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" @@ -3136,11 +3116,6 @@ fast-json-stable-stringify@^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= -fast-levenshtein@~1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz#0178dcdee023b92905193af0959e8a7639cfdcb9" - integrity sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk= - fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -3190,14 +3165,6 @@ filename-regex@^2.0.0: resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" integrity sha1-mW4+gEebmLmJfxWopYs9CE6SZ3U= -fileset@0.2.x: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fileset/-/fileset-0.2.1.tgz#588ef8973c6623b2a76df465105696b96aac8067" - integrity sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc= - dependencies: - glob "5.x" - minimatch "2.x" - fill-range@^2.1.0: version "2.2.3" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" @@ -3579,14 +3546,6 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getmac@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/getmac/-/getmac-1.4.1.tgz#cfefcb3ee7d7a73cba5292129cb100c19afbe17a" - integrity sha512-mQp+8D+grQX0gG8EJn6VfH0PxE56ZKNsTguOMxPShAiVk9lvH8Ey36eXepG705Ac1HCsvaSrQ/6bPHZ0++F/Mg== - dependencies: - editions "^1.3.4" - extract-opts "^3.2.0" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -3682,7 +3641,7 @@ glob@3.2.11: inherits "2" minimatch "0.3" -glob@5.x, glob@^5.0.13, glob@^5.0.15, glob@^5.0.3: +glob@^5.0.13, glob@^5.0.3: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= @@ -3753,7 +3712,7 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.0.1: +globals@^11.0.1, globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== @@ -3804,10 +3763,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" @@ -3948,14 +3907,15 @@ gulp-plumber@^1.2.0: plugin-error "^0.1.2" through2 "^2.0.3" -gulp-remote-src@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.4.tgz#4a4d18fac0ffedde94a7855953de90db00a1d1b1" - integrity sha512-mo7lGgZmNXyTbcUzfjSnUVkx1pnqqiwv/pPaIrYdTO77hq0WNTxXLAzQdoYOnyJ0mfVLNmNl9AGqWLiAzTPMMA== +gulp-remote-retry-src@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/gulp-remote-retry-src/-/gulp-remote-retry-src-0.6.0.tgz#fdcb5d5c9e67c31ae378a2a886ddad3d47913bb1" + integrity sha512-lFxpwwbM/GEIdYiNumxiUcPHZUROFJaF1zTBne1H8b3Pwx6Te6O9uEYp++JZPP62jdheOWcHUTBREiMkpdbm4Q== dependencies: event-stream "3.3.4" node.extend "~1.1.2" request "^2.88.0" + requestretry "^4.0.0" through2 "~2.0.3" vinyl "~2.0.1" @@ -4083,16 +4043,16 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" -handlebars@^4.0.1: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= +handlebars@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" + integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== dependencies: - async "^1.4.0" + neo-async "^2.6.0" optimist "^0.6.1" - source-map "^0.4.4" + source-map "^0.6.1" optionalDependencies: - uglify-js "^2.6" + uglify-js "^3.1.4" har-schema@^2.0.0: version "2.0.0" @@ -4202,6 +4162,13 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -4961,45 +4928,50 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul@0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" - integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= - dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.8.x" - esprima "2.7.x" - glob "^5.0.15" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" +istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== -istanbul@^0.3.17: - version "0.3.22" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.3.22.tgz#3e164d85021fe19c985d1f0e7ef0c3e22d012eb6" - integrity sha1-PhZNhQIf4ZyYXR8OfvDD4i0BLrY= +istanbul-lib-instrument@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" + integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.7.x" - esprima "2.5.x" - fileset "0.2.x" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" + "@babel/generator" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" + istanbul-lib-coverage "^2.0.5" + semver "^6.0.0" + +istanbul-lib-report@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" + integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== + dependencies: + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + supports-color "^6.1.0" + +istanbul-lib-source-maps@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" + integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== + dependencies: + handlebars "^4.1.2" istextorbinary@1.0.2: version "1.0.2" @@ -5051,14 +5023,6 @@ js-yaml@3.6.1: argparse "^1.0.7" esprima "^2.6.0" -js-yaml@3.x: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" - integrity sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - js-yaml@^3.12.0: version "3.12.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" @@ -5108,6 +5072,11 @@ jsdom-no-contextify@^3.1.0: xml-name-validator "^1.0.0" xmlhttprequest ">= 1.6.0 < 2.0.0" +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-edm-parser@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/json-edm-parser/-/json-edm-parser-0.1.2.tgz#1e60b0fef1bc0af67bc0d146dfdde5486cd615b4" @@ -5201,13 +5170,13 @@ just-debounce@^1.0.0: resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= -keytar@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.2.1.tgz#8a06a6577fdf6373e0aa6b112277e63dec77fd12" - integrity sha1-igamV3/fY3PgqmsRInfmPex3/RI= +keytar@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.11.0.tgz#891569045b287a0dabe69320e2381e059b02363f" + integrity sha512-cGn2xd4NY0yCBrU5zQ/lwIagP1UBOhUEemi6iSJU2gshN1RHkxHekSdLUji9IWNo5B1Va/iwXXWzGD2p8ziqfQ== dependencies: - nan "2.8.0" - prebuild-install "^2.4.1" + nan "2.14.0" + prebuild-install "5.3.0" kind-of@^1.1.0: version "1.1.0" @@ -5260,11 +5229,6 @@ last-run@^1.1.0: default-resolution "^2.0.0" es6-weak-map "^2.0.1" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= - lazy.js@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/lazy.js/-/lazy.js-0.4.3.tgz#87f67a07ad36555121e4fff1520df31be66786d8" @@ -5311,14 +5275,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -levn@~0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.2.5.tgz#ba8d339d0ca4a610e3a3f145b9caf48807155054" - integrity sha1-uo0znQykphDjo/FFucr0iAcVUFQ= - dependencies: - prelude-ls "~1.1.0" - type-check "~0.3.1" - liftoff@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" @@ -5476,11 +5432,6 @@ long@^3.2.0: resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= - loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -5530,6 +5481,14 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + make-error-cause@^1.1.1: version "1.2.2" resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d" @@ -5825,13 +5784,6 @@ minimatch@0.3: dependencies: brace-expansion "^1.1.7" -minimatch@2.x: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= - dependencies: - brace-expansion "^1.0.0" - minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -5993,21 +5945,11 @@ mute-stream@0.0.7, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" - integrity sha1-7XFfP+neArV6XmJS2QqWZ14fCFo= - -nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: +nan@2.14.0, nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: version "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" @@ -6035,6 +5977,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-build-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" + integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== + native-is-elevated@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/native-is-elevated/-/native-is-elevated-0.2.1.tgz#70a2123a8575b9f624a3ef465d98cb74ae017385" @@ -6074,15 +6021,20 @@ neo-async@^2.5.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" integrity sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA== +neo-async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" integrity sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA== -node-abi@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.4.1.tgz#7628c4d4ec4e9cd3764ceb3652f36b2e7f8d4923" - integrity sha512-pUlswqpHQ7zGPI9lGjZ4XDNIEUDbHxsltfIRb7dTnYdhgHWHOcB0MLZKLoCz6UMcGzSPG5wGl1HODZVQAUsH6w== +node-abi@^2.7.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.9.0.tgz#ae4075b298dab2d92dd1e22c48ccc7ffd7f06200" + integrity sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA== dependencies: semver "^5.4.1" @@ -6136,26 +6088,27 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-pty@0.9.0-beta17: - version "0.9.0-beta17" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta17.tgz#9b490df86a8124dea595e9fbedeaaf4b2eedbbcb" - integrity sha512-E94XwIs3JxLKAboquHY9Kytbbj/T/tJtRpQoAUdfPE7UXRta/NV+xdmRNhZkeU9jCji+plm656GbYFievgNPkQ== +node-pty@0.9.0-beta19: + version "0.9.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta19.tgz#0fd381b2006f4665c4c2ee0509219e591842371a" + integrity sha512-MkKEvBnauGnzgXNr/oaoWQLVXm1gheIKZs4YQp8883ZiETmbEnpSvD0FU3bELcPXG5VFPRqIGsQJ4KUMBLzkPA== dependencies: nan "^2.13.2" node.extend@~1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.6.tgz#a7b882c82d6c93a4863a5504bd5de8ec86258b96" - integrity sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y= + version "1.1.8" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" + integrity sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA== dependencies: - is "^3.1.0" + has "^1.0.3" + is "^3.2.1" noop-logger@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= -nopt@3.x, nopt@^3.0.1: +nopt@^3.0.1: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= @@ -6405,7 +6358,7 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -6424,12 +6377,12 @@ onigasm-umd@^2.2.2: resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== -oniguruma@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.0.2.tgz#a5c922cf7066da1dbcc60f6385a90437a83f8d0b" - integrity sha512-zCsdNxTrrB4yVPMxhcIODGv1p4NVBu9WvsWnIGhMpu5djO4MQWXrC7YKjtza+OyoRqqgy27CqYWa1h5e2DDbig== +oniguruma@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af" + integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA== dependencies: - nan "^2.10.0" + nan "^2.14.0" opener@~1.4.0: version "1.4.3" @@ -6458,19 +6411,7 @@ optimist@0.6.x, optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.5.0.tgz#b75a8995a2d417df25b6e4e3862f50aa88651368" - integrity sha1-t1qJlaLUF98ltuTjhi9QqohlE2g= - dependencies: - deep-is "~0.1.2" - fast-levenshtein "~1.0.0" - levn "~0.2.5" - prelude-ls "~1.1.1" - type-check "~0.3.1" - wordwrap "~0.0.2" - -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= @@ -6845,6 +6786,11 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -7153,28 +7099,29 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0 source-map "^0.5.6" supports-color "^3.2.3" -prebuild-install@^2.4.1: - version "2.5.3" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.5.3.tgz#9f65f242782d370296353710e9bc843490c19f69" - integrity sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g== +prebuild-install@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" + integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== dependencies: detect-libc "^1.0.3" - expand-template "^1.0.2" + expand-template "^2.0.3" github-from-package "0.0.0" minimist "^1.2.0" mkdirp "^0.5.1" - node-abi "^2.2.0" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" noop-logger "^0.1.1" npmlog "^4.0.1" os-homedir "^1.0.1" pump "^2.0.1" - rc "^1.1.6" + rc "^1.2.7" simple-get "^2.7.0" tar-fs "^1.13.0" tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" -prelude-ls@~1.1.0, prelude-ls@~1.1.1, prelude-ls@~1.1.2: +prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= @@ -7460,7 +7407,7 @@ rc@^1.1.2: minimist "^1.2.0" strip-json-comments "~2.0.1" -rc@^1.1.6, rc@^1.2.7: +rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7647,17 +7594,6 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -remap-istanbul@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/remap-istanbul/-/remap-istanbul-0.13.0.tgz#a529dfd080bb760f5274e3671c9c065f29923ed1" - integrity sha512-rS5ZpVAx3fGtKZkiBe1esXg5mKYbgW9iz8kkADFt3p6lo3NsBBUX1q6SwdhwUtYCGnr7nK6gRlbYK3i8R0jbRA== - dependencies: - istanbul "0.4.5" - minimatch "^3.0.4" - plugin-error "^1.0.1" - source-map "0.6.1" - through2 "3.0.0" - remove-bom-buffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" @@ -7810,6 +7746,15 @@ request@^2.86.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +requestretry@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-4.0.0.tgz#4e9e7280a7d8561bf33e9925264cf026e2be3e89" + integrity sha512-ST8m0+5FQH2FA+gbzUQyOQjUwHf22kbPQnd6TexveR0p+2UV1YYBg+Roe7BnKQ1Bb/+LtJwwm0QzxK2NA20Cug== + dependencies: + extend "^3.0.2" + lodash "^4.17.10" + when "^3.7.7" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -7880,11 +7825,6 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.x: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" @@ -7912,14 +7852,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= - dependencies: - align-text "^0.1.1" - -rimraf@2: +rimraf@2, rimraf@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -8055,6 +7988,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" @@ -8075,6 +8013,11 @@ semver@^5.5.1, semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" + integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -8329,11 +8272,6 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" @@ -8341,17 +8279,15 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= - dependencies: - amdefine ">=0.0.4" +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== sparkles@^1.0.0: version "1.0.0" @@ -8668,7 +8604,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.1.0, supports-color@^3.2.3: +supports-color@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= @@ -8696,6 +8632,13 @@ supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + sver-compat@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" @@ -8828,14 +8771,6 @@ through2@2.0.3, through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0 readable-stream "^2.1.5" xtend "~4.0.1" -through2@3.0.0, through2@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.0.tgz#468b461df9cd9fcc170f22ebf6852e467e578ff2" - integrity sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ== - dependencies: - readable-stream "2 || 3" - xtend "~4.0.1" - through2@^0.6.0: version "0.6.5" resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" @@ -8844,6 +8779,14 @@ through2@^0.6.0: readable-stream ">=1.0.33-1 <1.1.0-0" xtend ">=4.0.0 <4.1.0-0" +through2@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.0.tgz#468b461df9cd9fcc170f22ebf6852e467e578ff2" + integrity sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ== + dependencies: + readable-stream "2 || 3" + xtend "~4.0.1" + through2@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" @@ -8923,6 +8866,11 @@ to-buffer@^1.1.0: resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-iso-string@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" @@ -8992,6 +8940,11 @@ trim-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" @@ -9071,7 +9024,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-check@~0.3.1, type-check@~0.3.2: +type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= @@ -9086,13 +9039,6 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" -typechecker@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.5.0.tgz#c382920097812364bbaf4595b0ab6588244117a6" - integrity sha512-bqPE/ck3bVIaXP7gMKTKSHrypT32lpYTpiqzPYeYzdSQnmaGvaGhy7TnN/M/+5R+2rs/kKcp9ZLPRp/Q9Yj+4w== - dependencies: - editions "^1.3.4" - typed-rest-client@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-0.9.0.tgz#f768cc0dc3f4e950f06e04825c36b3e7834aa1f2" @@ -9145,16 +9091,6 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" -uglify-js@^2.6: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - uglify-js@^3.0.5: version "3.1.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.1.9.tgz#dffca799308cf327ec3ac77eeacb8e196ce3b452" @@ -9163,10 +9099,13 @@ uglify-js@^3.0.5: commander "~2.11.0" source-map "~0.6.1" -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= +uglify-js@^3.1.4: + version "3.6.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" + integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg== + dependencies: + commander "~2.20.0" + source-map "~0.6.1" uglifyjs-webpack-plugin@^1.2.4: version "1.2.7" @@ -9640,10 +9579,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.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" + integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== vscode-sqlite3@4.0.8: version "4.0.8" @@ -9652,12 +9591,12 @@ vscode-sqlite3@4.0.8: dependencies: nan "^2.14.0" -vscode-textmate@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.1.1.tgz#857e836fbc13a376ec624242437e1747d79610a9" - integrity sha512-xBjq9LH6fMhWDhIVkbKlB1JeCu6lT3FI/QKN24Xi4RKPBUm16IhHTqs6Q6SUGewkNsFZGkb1tJdZsuMnlmVpgw== +vscode-textmate@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" + integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== dependencies: - oniguruma "^7.0.0" + oniguruma "^7.2.0" vscode-windows-ca-certs@0.1.0: version "0.1.0" @@ -9763,6 +9702,11 @@ webpack@^4.16.5, webpack@^4.7.0: watchpack "^1.5.0" webpack-sources "^1.0.1" +when@^3.7.7: + version "3.7.8" + resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" + integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I= + whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" @@ -9783,13 +9727,6 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.1.1, which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg== - dependencies: - isexe "^2.0.0" - which@^1.2.14: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -9797,6 +9734,13 @@ which@^1.2.14: dependencies: isexe "^2.0.0" +which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -9804,46 +9748,36 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= +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-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-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.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.2.3.tgz#6b781f0a320e8a0d6434c9399add4389c709cf6e" - integrity sha512-SzPJSubVVsToz1g5lr2P+4mQT70gvJ9u/nlnpfkOeQcAhOuhKz5DiO1TARgR0OnVsv21LPzxbA2m/4JQkGh1wA== +windows-process-tree@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.2.4.tgz#747af587b54cc6c996f2be0836cc8a8fd0dc038f" + integrity sha512-9gag9AHm3Iin/4YC1EwoIfZlqW/rG2eV7rJZ4Fy5NnAMGdewmnwsie5Rz+CJo2vSolqzzfw7hPeu3oOdniNejg== dependencies: - nan "^2.10.0" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= - -wordwrap@^1.0.0, wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + nan "^2.13.2" wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + worker-farm@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" @@ -9951,20 +9885,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== xterm-addon-web-links@0.1.0-beta10: version "0.1.0-beta10" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta70: - version "3.15.0-beta70" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta70.tgz#3e81f32e8cd7147f9a0764fbe2599c277c697a74" - integrity sha512-VXhEbWwaxrs9Ac2KuTCmGX7Ktd0V+rVF5sdjXBsq/KBCtnUdwNzKnEjamNPsoNTDUv9y93INEbq82X7iBs1Gwg== +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== y18n@^3.2.1: version "3.2.1" @@ -10062,16 +9996,6 @@ yargs@^7.1.0: y18n "^3.2.1" yargs-parser "^5.0.0" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yauzl@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"