diff --git a/build/azure-pipelines/darwin/build.sh b/build/azure-pipelines/darwin/build.sh new file mode 100755 index 00000000000..af558b8c145 --- /dev/null +++ b/build/azure-pipelines/darwin/build.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -e +yarn gulp vscode-darwin-min +yarn gulp upload-vscode-sourcemaps \ 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 812e2034154..f5d5ef626b1 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -36,10 +36,7 @@ steps: set -e VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ - yarn gulp vscode-darwin-min - VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ - AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ - yarn gulp upload-vscode-sourcemaps + ./build/azure-pipelines/darwin/build.sh displayName: Build - script: | @@ -80,30 +77,12 @@ steps: - script: | set -e - - # remove pkg from archive - zip -d ../VSCode-darwin.zip "*.pkg" - - # publish the build - PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json` - VERSION=`node -p "require(\"$PACKAGEJSON\").version"` + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - node build/azure-pipelines/common/publish.js \ - "$(VSCODE_QUALITY)" \ - darwin \ - archive \ - "VSCode-darwin-$(VSCODE_QUALITY).zip" \ - $VERSION \ - true \ - ../VSCode-darwin.zip - - # publish hockeyapp symbols - node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_MACOS)" - - # upload configuration AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ - yarn gulp upload-vscode-configuration + AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ + VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ + ./build/azure-pipelines/darwin/publish.sh displayName: Publish - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 diff --git a/build/azure-pipelines/darwin/publish.sh b/build/azure-pipelines/darwin/publish.sh new file mode 100755 index 00000000000..96d5967ea4b --- /dev/null +++ b/build/azure-pipelines/darwin/publish.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# remove pkg from archive +zip -d ../VSCode-darwin.zip "*.pkg" + +# publish the build +PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json` +VERSION=`node -p "require(\"$PACKAGEJSON\").version"` +node build/azure-pipelines/common/publish.js \ + "$VSCODE_QUALITY" \ + darwin \ + archive \ + "VSCode-darwin-$VSCODE_QUALITY.zip" \ + $VERSION \ + true \ + ../VSCode-darwin.zip + +# publish hockeyapp symbols +node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS" + +# upload configuration +yarn gulp upload-vscode-configuration diff --git a/build/azure-pipelines/linux/build.sh b/build/azure-pipelines/linux/build.sh new file mode 100755 index 00000000000..bd251ebc789 --- /dev/null +++ b/build/azure-pipelines/linux/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +yarn gulp "vscode-linux-$VSCODE_ARCH-min" \ No newline at end of file diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 0a37474ccd5..342d72e4969 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -34,11 +34,13 @@ steps: yarn monaco-compile-check node build/azure-pipelines/common/installDistro.js node build/lib/builtInExtensions.js + displayName: Prepare build - script: | set -e - VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" yarn gulp vscode-linux-$(VSCODE_ARCH)-min - name: build + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ + ./build/azure-pipelines/linux/build.sh + displayName: Build - script: | set -e @@ -49,66 +51,16 @@ steps: DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)" - name: test + displayName: Run unit tests - script: | set -e - REPO="$(pwd)" - ROOT="$REPO/.." - ARCH="$(VSCODE_ARCH)" - - # Publish tarball - PLATFORM_LINUX="linux-$(VSCODE_ARCH)" - [[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64" - [[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64" - BUILDNAME="VSCode-$PLATFORM_LINUX" - BUILD="$ROOT/$BUILDNAME" - BUILD_VERSION="$(date +%s)" - [ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz" - TARBALL_PATH="$ROOT/$TARBALL_FILENAME" - PACKAGEJSON="$BUILD/resources/app/package.json" - VERSION=$(node -p "require(\"$PACKAGEJSON\").version") - - rm -rf $ROOT/code-*.tar.* - (cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME) - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH" - - # Publish hockeyapp symbols - node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_LINUX64)" - - # Publish DEB - yarn gulp "vscode-linux-$(VSCODE_ARCH)-build-deb" - PLATFORM_DEB="linux-deb-$ARCH" - [[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64" - DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)" - DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME" - - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - 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-$ARCH" - [[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || 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" - - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - 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" - - # 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" - rm -rf $SNAP_TARBALL_PATH - (cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap) + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ + VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ + ./build/azure-pipelines/linux/publish.sh + displayName: Publish - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' diff --git a/build/azure-pipelines/linux/publish.sh b/build/azure-pipelines/linux/publish.sh new file mode 100755 index 00000000000..ca338a6fc5f --- /dev/null +++ b/build/azure-pipelines/linux/publish.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -e +REPO="$(pwd)" +ROOT="$REPO/.." + +# Publish tarball +PLATFORM_LINUX="linux-$VSCODE_ARCH" +[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64" +[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64" +BUILDNAME="VSCode-$PLATFORM_LINUX" +BUILD="$ROOT/$BUILDNAME" +BUILD_VERSION="$(date +%s)" +[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz" +TARBALL_PATH="$ROOT/$TARBALL_FILENAME" +PACKAGEJSON="$BUILD/resources/app/package.json" +VERSION=$(node -p "require(\"$PACKAGEJSON\").version") + +rm -rf $ROOT/code-*.tar.* +(cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME) + +node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH" + +# Publish hockeyapp symbols +node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64" + +# Publish DEB +yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb" +PLATFORM_DEB="linux-deb-$VSCODE_ARCH" +[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64" +DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)" +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" +[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || 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" + +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" + +# 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" +rm -rf $SNAP_TARBALL_PATH +(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap) diff --git a/build/azure-pipelines/win32/build.ps1 b/build/azure-pipelines/win32/build.ps1 new file mode 100644 index 00000000000..60325ba54ca --- /dev/null +++ b/build/azure-pipelines/win32/build.ps1 @@ -0,0 +1,4 @@ +. build/azure-pipelines/win32/exec.ps1 +$ErrorActionPreference = "Stop" +exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min" } +exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } \ No newline at end of file diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 6352ef83760..a49349150d2 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -31,14 +31,14 @@ steps: exec { yarn monaco-compile-check } exec { node build/azure-pipelines/common/installDistro.js } exec { node build/lib/builtInExtensions.js } + displayName: Prepare build - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" $env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-min" } - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-inno-updater" } - name: build + .\build\azure-pipelines\win32\build.ps1 + displayName: Build - powershell: | . build/azure-pipelines/win32/exec.ps1 @@ -46,19 +46,19 @@ steps: exec { yarn gulp "electron-$(VSCODE_ARCH)" } exec { .\scripts\test.bat --build --tfs "Unit Tests" } # yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - displayName: Unit tests + displayName: Run unit tests - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" exec { yarn gulp "electron-$(VSCODE_ARCH)" } exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } - displayName: Integration tests + displayName: Run integration tests - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 inputs: ConnectedServiceName: 'ESRP CodeSign' - FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)' + FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)' Pattern: '*.dll,*.exe,*.node' signConfigType: inlineSignParams inlineOperation: | @@ -132,31 +132,11 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { yarn gulp "vscode-win32-$(VSCODE_ARCH)-archive" "vscode-win32-$(VSCODE_ARCH)-system-setup" "vscode-win32-$(VSCODE_ARCH)-user-setup" --sign } - - $Repo = "$(pwd)" - $Root = "$Repo\.." - $SystemExe = "$Repo\.build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe" - $UserExe = "$Repo\.build\win32-$(VSCODE_ARCH)\user-setup\VSCodeSetup.exe" - $Zip = "$Repo\.build\win32-$(VSCODE_ARCH)\archive\VSCode-win32-$(VSCODE_ARCH).zip" - $Build = "$Root\VSCode-win32-$(VSCODE_ARCH)" - - # get version - $PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json - $Version = $PackageJson.version - $Quality = "$env:VSCODE_QUALITY" $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)" $env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)" - - $assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" } - - exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$(VSCODE_ARCH)-$Version.zip" $Version true $Zip } - exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $SystemExe } - exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform-user" setup "VSCodeUserSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $UserExe } - - # publish hockeyapp symbols - $hockeyAppId = if ("$(VSCODE_ARCH)" -eq "ia32") { "$(VSCODE_HOCKEYAPP_ID_WIN32)" } else { "$(VSCODE_HOCKEYAPP_ID_WIN64)" } - exec { node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" $hockeyAppId } + $env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)" + .\build\azure-pipelines\win32\publish.ps1 + displayName: Publish - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' diff --git a/build/azure-pipelines/win32/publish.ps1 b/build/azure-pipelines/win32/publish.ps1 new file mode 100644 index 00000000000..8e6fa988adf --- /dev/null +++ b/build/azure-pipelines/win32/publish.ps1 @@ -0,0 +1,28 @@ +. build/azure-pipelines/win32/exec.ps1 +$ErrorActionPreference = "Stop" + +$Arch = "$env:VSCODE_ARCH" + +exec { yarn gulp "vscode-win32-$Arch-archive" "vscode-win32-$Arch-system-setup" "vscode-win32-$Arch-user-setup" --sign } + +$Repo = "$(pwd)" +$Root = "$Repo\.." +$SystemExe = "$Repo\.build\win32-$Arch\system-setup\VSCodeSetup.exe" +$UserExe = "$Repo\.build\win32-$Arch\user-setup\VSCodeSetup.exe" +$Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip" +$Build = "$Root\VSCode-win32-$Arch" + +# get version +$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json +$Version = $PackageJson.version +$Quality = "$env:VSCODE_QUALITY" + +$AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-x64" } + +exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-archive" archive "VSCode-win32-$Arch-$Version.zip" $Version true $Zip } +exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform" setup "VSCodeSetup-$Arch-$Version.exe" $Version true $SystemExe } +exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $Version true $UserExe } + +# publish hockeyapp symbols +$hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" } +exec { node build/azure-pipelines/common/symbols.js "$env:VSCODE_MIXIN_PASSWORD" "$env:VSCODE_HOCKEYAPP_TOKEN" "$Arch" $hockeyAppId } diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 2e077e83e4b..5d5d7ed7893 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -66,7 +66,7 @@ const vscodeResources = [ '!out-build/vs/code/browser/**/*.html', 'out-build/vs/base/common/performance.js', 'out-build/vs/base/node/languagePacks.js', - 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}', + 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/contrib/debug/**/*.json', diff --git a/cgmanifest.json b/cgmanifest.json index 927c66cbc37..01cdd8df5f1 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -111,11 +111,11 @@ "git": { "name": "vscode-octicons-font", "repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font", - "commitHash": "5095860bb929919670646e2dfa0ee47d9b93bcb9" + "commitHash": "4f69de3a233ed501c2098e33047e116ac2fbbf42" } }, "license": "MIT", - "version": "1.0.0" + "version": "1.1.0" }, { "component": { diff --git a/extensions/git/package.json b/extensions/git/package.json index 058fd6691a7..4395d306bb5 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1031,7 +1031,7 @@ ], "markdownDescription": "%config.path%", "default": null, - "scope": "application" + "scope": "machine" }, "git.autoRepositoryDetection": { "type": [ diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index cce1a6843eb..1ca17ec6059 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -5254,10 +5254,6 @@ }, "jsdoctype": { "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, { "contentName": "entity.name.type.instance.jsdoc", "begin": "\\G({)", diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 312e60b04a6..276b577ee0c 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -5254,10 +5254,6 @@ }, "jsdoctype": { "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, { "contentName": "entity.name.type.instance.jsdoc", "begin": "\\G({)", diff --git a/extensions/log/package.json b/extensions/log/package.json index 96fa29a0b30..38da616a8d4 100644 --- a/extensions/log/package.json +++ b/extensions/log/package.json @@ -19,7 +19,7 @@ "*.log.?" ], "aliases": [ - "log" + "Log" ] } ], diff --git a/extensions/typescript-basics/build/update-grammars.js b/extensions/typescript-basics/build/update-grammars.js index c41d9c335ca..527fa2c1d43 100644 --- a/extensions/typescript-basics/build/update-grammars.js +++ b/extensions/typescript-basics/build/update-grammars.js @@ -17,6 +17,20 @@ function removeDom(grammar) { return grammar; } +function patchJsdoctype(grammar) { + grammar.repository['jsdoctype'].patterns = grammar.repository['jsdoctype'].patterns.filter(pattern => { + if (pattern.name && pattern.name.indexOf('illegal') >= -1) { + return false; + } + return true; + }); + return grammar; +} + +function patchGrammar(grammar) { + return removeDom(patchJsdoctype(grammar)); +} + function adaptToJavaScript(grammar, replacementScope) { grammar.name = 'JavaScript (with React support)'; grammar.fileTypes = ['.js', '.jsx', '.es6', '.mjs']; @@ -44,7 +58,7 @@ function adaptToJavaScript(grammar, replacementScope) { } var tsGrammarRepo = 'Microsoft/TypeScript-TmLanguage'; -updateGrammar.update(tsGrammarRepo, 'TypeScript.tmLanguage', './syntaxes/TypeScript.tmLanguage.json', grammar => removeDom(grammar)); -updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', './syntaxes/TypeScriptReact.tmLanguage.json', grammar => removeDom(grammar)); -updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScript.tmLanguage.json', grammar => adaptToJavaScript(removeDom(grammar), '.js')); -updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScriptReact.tmLanguage.json', grammar => adaptToJavaScript(removeDom(grammar), '.js.jsx')); +updateGrammar.update(tsGrammarRepo, 'TypeScript.tmLanguage', './syntaxes/TypeScript.tmLanguage.json', grammar => patchGrammar(grammar)); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', './syntaxes/TypeScriptReact.tmLanguage.json', grammar => patchGrammar(grammar)); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScript.tmLanguage.json', grammar => adaptToJavaScript(patchGrammar(grammar), '.js')); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScriptReact.tmLanguage.json', grammar => adaptToJavaScript(patchGrammar(grammar), '.js.jsx')); diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index 3f697de5ced..f5532d15dd3 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -79,18 +79,8 @@ } }, { - "scopeName": "documentation.markdown.injection", - "path": "./syntaxes/MarkdownDocumentationInjection.tmLanguage.json", - "injectTo": [ - "source.ts", - "source.tsx", - "source.js", - "source.js.jsx" - ] - }, - { - "scopeName": "documentation.example.injection", - "path": "./syntaxes/ExampleJsDoc.injection.tmLanguage.json", + "scopeName": "documentation.injection", + "path": "./syntaxes/jsdoc.injection.tmLanguage.json", "injectTo": [ "source.ts", "source.tsx", diff --git a/extensions/typescript-basics/syntaxes/MarkdownDocumentationInjection.tmLanguage.json b/extensions/typescript-basics/syntaxes/MarkdownDocumentationInjection.tmLanguage.json deleted file mode 100644 index 4794b38e2e1..00000000000 --- a/extensions/typescript-basics/syntaxes/MarkdownDocumentationInjection.tmLanguage.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "injectionSelector": "L:comment.block.documentation", - "patterns": [ - { - "include": "#markdown-comment" - } - ], - "repository": { - "markdown-comment": { - "begin": "(?<=/\\*\\*)([^*]|\\*(?!/))*$", - "while": "(^|\\G)\\s*\\*(?!/)(?=([^*]|[*](?!/))*$)", - "patterns": [ - { - "include": "text.html.markdown#fenced_code_block" - }, - { - "include": "text.html.markdown#lists" - }, - { - "include": "source.ts#docblock" - }, - { - "include": "text.html.markdown#inline" - } - ] - } - }, - "scopeName": "documentation.markdown.injection" -} \ No newline at end of file diff --git a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json index 9d153014bac..cdfe6fd83bf 100644 --- a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json @@ -5303,10 +5303,6 @@ }, "jsdoctype": { "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, { "contentName": "entity.name.type.instance.jsdoc", "begin": "\\G({)", diff --git a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json index 7dd0b2755fa..3d6f484970b 100644 --- a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json @@ -5254,10 +5254,6 @@ }, "jsdoctype": { "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, { "contentName": "entity.name.type.instance.jsdoc", "begin": "\\G({)", diff --git a/extensions/typescript-basics/syntaxes/ExampleJsDoc.injection.tmLanguage.json b/extensions/typescript-basics/syntaxes/jsdoc.injection.tmLanguage.json similarity index 51% rename from extensions/typescript-basics/syntaxes/ExampleJsDoc.injection.tmLanguage.json rename to extensions/typescript-basics/syntaxes/jsdoc.injection.tmLanguage.json index 03c52cb97ff..b7b4db2d2a5 100644 --- a/extensions/typescript-basics/syntaxes/ExampleJsDoc.injection.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/jsdoc.injection.tmLanguage.json @@ -2,10 +2,31 @@ "injectionSelector": "L:comment.block.documentation", "patterns": [ { - "include": "#example" + "include": "#jsdocbody" } ], "repository": { + "jsdocbody": { + "begin": "(?<=/\\*\\*)([^*]|\\*(?!/))*$", + "while": "(^|\\G)\\s*\\*(?!/)(?=([^*]|[*](?!/))*$)", + "patterns": [ + { + "include": "text.html.markdown#fenced_code_block" + }, + { + "include": "text.html.markdown#lists" + }, + { + "include": "#example" + }, + { + "include": "source.ts#docblock" + }, + { + "include": "text.html.markdown#inline" + } + ] + }, "example": { "begin": "((@)example)\\s+(?=([^*]|[*](?!/))*$).*$", "while": "(^|\\G)\\s(?!@)(?=([^*]|[*](?!/))*$)", @@ -25,5 +46,5 @@ ] } }, - "scopeName": "documentation.example.injection" + "scopeName": "documentation.injection" } \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts new file mode 100644 index 00000000000..411f9bbede3 --- /dev/null +++ b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-example.ts @@ -0,0 +1,8 @@ +/** + * @example + * 1 + 1 + * + * @other + * not colored + */ +const a = 1 \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts new file mode 100644 index 00000000000..136f8b1bafb --- /dev/null +++ b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-markdown.ts @@ -0,0 +1,7 @@ +/** + * **Bold** + * ```js + * 1 + code + * ``` + */ +const a = 1 \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-multiline-type.ts b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-multiline-type.ts new file mode 100644 index 00000000000..eda831efe02 --- /dev/null +++ b/extensions/typescript-basics/test/colorize-fixtures/test-jsdoc-multiline-type.ts @@ -0,0 +1,22 @@ +/** + * @typedef {{ + * id: number, + * fn: !Function, + * context: (!Object|undefined) + * }} + * @private + */ +goog.dom.animationFrame.Task_; + + +/** + * @typedef {{ + * measureTask: goog.dom.animationFrame.Task_, + * mutateTask: goog.dom.animationFrame.Task_, + * state: (!Object|undefined), + * args: (!Array|undefined), + * isScheduled: boolean + * }} + * @private + */ +goog.dom.animationFrame.TaskSet_; \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json b/extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json new file mode 100644 index 00000000000..ea15234c214 --- /dev/null +++ b/extensions/typescript-basics/test/colorize-results/test-jsdoc-example_ts.json @@ -0,0 +1,277 @@ +[ + { + "c": "/**", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "example", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "1", + "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts constant.numeric.decimal.tsx", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "+", + "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts keyword.operator.arithmetic.tsx", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "1", + "t": "source.ts comment.block.documentation.ts meta.embedded.block.example.source.ts constant.numeric.decimal.tsx", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "other", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " * not colored", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "*/", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "const", + "t": "source.ts meta.var.expr.ts storage.type.ts", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.ts meta.var.expr.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "a", + "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts meta.definition.variable.ts variable.other.constant.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " ", + "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.ts meta.var.expr.ts keyword.operator.assignment.ts", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.ts meta.var.expr.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "1", + "t": "source.ts meta.var.expr.ts constant.numeric.decimal.ts", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + } +] \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json b/extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json new file mode 100644 index 00000000000..eea45a645eb --- /dev/null +++ b/extensions/typescript-basics/test/colorize-results/test-jsdoc-markdown_ts.json @@ -0,0 +1,310 @@ +[ + { + "c": "/**", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "**", + "t": "source.ts comment.block.documentation.ts markup.bold.markdown punctuation.definition.bold.markdown", + "r": { + "dark_plus": "markup.bold: #569CD6", + "light_plus": "markup.bold: #000080", + "dark_vs": "markup.bold: #569CD6", + "light_vs": "markup.bold: #000080", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "Bold", + "t": "source.ts comment.block.documentation.ts markup.bold.markdown", + "r": { + "dark_plus": "markup.bold: #569CD6", + "light_plus": "markup.bold: #000080", + "dark_vs": "markup.bold: #569CD6", + "light_vs": "markup.bold: #000080", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "**", + "t": "source.ts comment.block.documentation.ts markup.bold.markdown punctuation.definition.bold.markdown", + "r": { + "dark_plus": "markup.bold: #569CD6", + "light_plus": "markup.bold: #000080", + "dark_vs": "markup.bold: #569CD6", + "light_vs": "markup.bold: #000080", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "```", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown punctuation.definition.markdown", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "js", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "1", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript constant.numeric.decimal.js", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "+", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript keyword.operator.arithmetic.js", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "code", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown meta.embedded.block.javascript variable.other.readwrite.js", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "```", + "t": "source.ts comment.block.documentation.ts markup.fenced_code.block.markdown punctuation.definition.markdown", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "*/", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "const", + "t": "source.ts meta.var.expr.ts storage.type.ts", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.ts meta.var.expr.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "a", + "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts meta.definition.variable.ts variable.other.constant.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " ", + "t": "source.ts meta.var.expr.ts meta.var-single-variable.expr.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.ts meta.var.expr.ts keyword.operator.assignment.ts", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.ts meta.var.expr.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "1", + "t": "source.ts meta.var.expr.ts constant.numeric.decimal.ts", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + } +] \ No newline at end of file diff --git a/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json b/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json new file mode 100644 index 00000000000..cc1eba5f197 --- /dev/null +++ b/extensions/typescript-basics/test/colorize-results/test-jsdoc-multiline-type_ts.json @@ -0,0 +1,684 @@ +[ + { + "c": "/**", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "typedef", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "{", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc punctuation.definition.bracket.curly.begin.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": "{", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " id: number,", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " fn: !Function,", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " context: (!Object|undefined)", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " }", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": "}", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc punctuation.definition.bracket.curly.end.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "private", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "*/", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "goog", + "t": "source.ts variable.other.object.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.ts punctuation.accessor.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "dom", + "t": "source.ts variable.other.object.property.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.ts punctuation.accessor.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "animationFrame", + "t": "source.ts variable.other.object.property.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.ts punctuation.accessor.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "Task_", + "t": "source.ts variable.other.property.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ";", + "t": "source.ts punctuation.terminator.statement.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "/**", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "typedef", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "{", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc punctuation.definition.bracket.curly.begin.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": "{", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " measureTask: goog.dom.animationFrame.Task_,", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " mutateTask: goog.dom.animationFrame.Task_,", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " state: (!Object|undefined),", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " args: (!Array|undefined),", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " isScheduled: boolean", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " *", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " }", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": "}", + "t": "source.ts comment.block.documentation.ts entity.name.type.instance.jsdoc punctuation.definition.bracket.curly.end.jsdoc", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " * ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc punctuation.definition.block.tag.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "private", + "t": "source.ts comment.block.documentation.ts storage.type.class.jsdoc", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.ts comment.block.documentation.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "*/", + "t": "source.ts comment.block.documentation.ts punctuation.definition.comment.ts", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "goog", + "t": "source.ts variable.other.object.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.ts punctuation.accessor.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "dom", + "t": "source.ts variable.other.object.property.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.ts punctuation.accessor.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "animationFrame", + "t": "source.ts variable.other.object.property.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.ts punctuation.accessor.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "TaskSet_", + "t": "source.ts variable.other.property.ts", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ";", + "t": "source.ts punctuation.terminator.statement.ts", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + } +] \ No newline at end of file diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 89194ce1945..f5516fd5f98 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -83,7 +83,7 @@ ], "default": null, "description": "%typescript.npm%", - "scope": "application" + "scope": "machine" }, "typescript.check.npmIsInstalled": { "type": "boolean", @@ -129,7 +129,7 @@ }, "default": [], "description": "%typescript.tsserver.pluginPaths%", - "scope": "application" + "scope": "machine" }, "typescript.tsserver.trace": { "type": "string", diff --git a/extensions/typescript-language-features/src/features/completions.ts b/extensions/typescript-language-features/src/features/completions.ts index d5822dede34..6d9cb0498c7 100644 --- a/extensions/typescript-language-features/src/features/completions.ts +++ b/extensions/typescript-language-features/src/features/completions.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; -import { ITypeScriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import API from '../utils/api'; import { nulToken } from '../utils/cancellation'; import { applyCodeAction } from '../utils/codeAction'; @@ -15,10 +15,11 @@ import { Command, CommandManager } from '../utils/commandManager'; import { ConfigurationDependentRegistration } from '../utils/dependentRegistration'; import { memoize } from '../utils/memoize'; import * as Previewer from '../utils/previewer'; +import { snippetForFunctionCall } from '../utils/snippetForFunctionCall'; +import TelemetryReporter from '../utils/telemetry'; import * as typeConverters from '../utils/typeConverters'; import TypingsStatus from '../utils/typingsStatus'; import FileConfigurationManager from './fileConfigurationManager'; -import { snippetForFunctionCall } from '../utils/snippetForFunctionCall'; const localize = nls.loadMessageBundle(); @@ -333,6 +334,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider private readonly typingsStatus: TypingsStatus, private readonly fileConfigurationManager: FileConfigurationManager, commandManager: CommandManager, + private readonly telemetryReporter: TelemetryReporter, onCompletionAccepted: (item: vscode.CompletionItem) => void ) { commandManager.register(new ApplyCompletionCodeActionCommand(this.client)); @@ -385,7 +387,28 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider let entries: ReadonlyArray; let metadata: any | undefined; if (this.client.apiVersion.gte(API.v300)) { - const response = await this.client.interruptGetErr(() => this.client.execute('completionInfo', args, token)); + const startTime = Date.now(); + let response: ServerResponse.Response | undefined; + try { + response = await this.client.interruptGetErr(() => this.client.execute('completionInfo', args, token)); + } finally { + const duration: number = Date.now() - startTime; + + /* __GDPR__ + "completions.execute" : { + "duration" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "type" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "${include}": [ + "${TypeScriptCommonProperties}", + ] + } + */ + this.telemetryReporter.logTelemetry('completions.execute', { + duration: duration + '', + type: response ? response.type : 'unknown' + }); + } + if (response.type !== 'response' || !response.body) { return null; } @@ -677,10 +700,11 @@ export function register( typingsStatus: TypingsStatus, fileConfigurationManager: FileConfigurationManager, commandManager: CommandManager, + telemetryReporter: TelemetryReporter, onCompletionAccepted: (item: vscode.CompletionItem) => void ) { return new ConfigurationDependentRegistration(modeId, 'suggest.enabled', () => vscode.languages.registerCompletionItemProvider(selector, - new TypeScriptCompletionItemProvider(client, modeId, typingsStatus, fileConfigurationManager, commandManager, onCompletionAccepted), + new TypeScriptCompletionItemProvider(client, modeId, typingsStatus, fileConfigurationManager, commandManager, telemetryReporter, onCompletionAccepted), ...TypeScriptCompletionItemProvider.triggerCharacters)); } diff --git a/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts b/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts index 7b30b68a658..0b1ddeca929 100644 --- a/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts +++ b/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts @@ -36,6 +36,8 @@ const directives: Directive[] = [ ]; class DirectiveCommentCompletionProvider implements vscode.CompletionItemProvider { + public static readonly minVersion = API.v230; + constructor( private readonly client: ITypeScriptServiceClient, ) { } @@ -69,7 +71,7 @@ export function register( selector: vscode.DocumentSelector, client: ITypeScriptServiceClient, ) { - return new VersionDependentRegistration(client, API.v230, () => { + return new VersionDependentRegistration(client, DirectiveCommentCompletionProvider.minVersion, () => { return vscode.languages.registerCompletionItemProvider(selector, new DirectiveCommentCompletionProvider(client), '@'); diff --git a/extensions/typescript-language-features/src/features/folding.ts b/extensions/typescript-language-features/src/features/folding.ts index 228cb744a53..a00a2db5f00 100644 --- a/extensions/typescript-language-features/src/features/folding.ts +++ b/extensions/typescript-language-features/src/features/folding.ts @@ -11,6 +11,8 @@ import { VersionDependentRegistration } from '../utils/dependentRegistration'; import * as typeConverters from '../utils/typeConverters'; class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider { + public static readonly minVersion = API.v280; + public constructor( private readonly client: ITypeScriptServiceClient ) { } @@ -75,7 +77,7 @@ export function register( selector: vscode.DocumentSelector, client: ITypeScriptServiceClient, ): vscode.Disposable { - return new VersionDependentRegistration(client, API.v280, () => { + return new VersionDependentRegistration(client, TypeScriptFoldingProvider.minVersion, () => { return vscode.languages.registerFoldingRangeProvider(selector, new TypeScriptFoldingProvider(client)); }); diff --git a/extensions/typescript-language-features/src/features/implementations.ts b/extensions/typescript-language-features/src/features/implementations.ts index d750587ea8d..7b7dc130175 100644 --- a/extensions/typescript-language-features/src/features/implementations.ts +++ b/extensions/typescript-language-features/src/features/implementations.ts @@ -10,6 +10,8 @@ import { VersionDependentRegistration } from '../utils/dependentRegistration'; import DefinitionProviderBase from './definitionProviderBase'; class TypeScriptImplementationProvider extends DefinitionProviderBase implements vscode.ImplementationProvider { + public static readonly minVersion = API.v220; + public provideImplementation(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { return this.getSymbolLocations('implementation', document, position, token); } @@ -19,7 +21,7 @@ export function register( selector: vscode.DocumentSelector, client: ITypeScriptServiceClient, ) { - return new VersionDependentRegistration(client, API.v220, () => { + return new VersionDependentRegistration(client, TypeScriptImplementationProvider.minVersion, () => { return vscode.languages.registerImplementationProvider(selector, new TypeScriptImplementationProvider(client)); }); diff --git a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts index e2f7dc2b531..63cfc6222d9 100644 --- a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts +++ b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts @@ -17,6 +17,7 @@ import * as typeConverters from '../utils/typeConverters'; const localize = nls.loadMessageBundle(); export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider { + public static readonly minVersion = API.v220; public async resolveCodeLens( inputCodeLens: vscode.CodeLens, @@ -95,7 +96,7 @@ export function register( client: ITypeScriptServiceClient, cachedResponse: CachedResponse, ) { - return new VersionDependentRegistration(client, API.v220, () => + return new VersionDependentRegistration(client, TypeScriptImplementationsCodeLensProvider.minVersion, () => new ConfigurationDependentRegistration(modeId, 'implementationsCodeLens.enabled', () => { return vscode.languages.registerCodeLensProvider(selector, new TypeScriptImplementationsCodeLensProvider(client, cachedResponse)); diff --git a/extensions/typescript-language-features/src/features/organizeImports.ts b/extensions/typescript-language-features/src/features/organizeImports.ts index aeb1efae11f..cbae287db1e 100644 --- a/extensions/typescript-language-features/src/features/organizeImports.ts +++ b/extensions/typescript-language-features/src/features/organizeImports.ts @@ -57,6 +57,8 @@ class OrganizeImportsCommand implements Command { } export class OrganizeImportsCodeActionProvider implements vscode.CodeActionProvider { + public static readonly minVersion = API.v280; + public constructor( private readonly client: ITypeScriptServiceClient, commandManager: CommandManager, @@ -103,7 +105,7 @@ export function register( fileConfigurationManager: FileConfigurationManager, telemetryReporter: TelemetryReporter, ) { - return new VersionDependentRegistration(client, API.v280, () => { + return new VersionDependentRegistration(client, OrganizeImportsCodeActionProvider.minVersion, () => { const organizeImportsProvider = new OrganizeImportsCodeActionProvider(client, commandManager, fileConfigurationManager, telemetryReporter); return vscode.languages.registerCodeActionsProvider(selector, organizeImportsProvider, diff --git a/extensions/typescript-language-features/src/features/quickFix.ts b/extensions/typescript-language-features/src/features/quickFix.ts index 91c3f3b3265..8972df52185 100644 --- a/extensions/typescript-language-features/src/features/quickFix.ts +++ b/extensions/typescript-language-features/src/features/quickFix.ts @@ -174,6 +174,7 @@ class SupportedCodeActionProvider { } class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { + public static readonly minVersion = API.v213; public static readonly metadata: vscode.CodeActionProviderMetadata = { providedCodeActionKinds: [vscode.CodeActionKind.QuickFix] @@ -326,7 +327,7 @@ export function register( diagnosticsManager: DiagnosticsManager, telemetryReporter: TelemetryReporter ) { - return new VersionDependentRegistration(client, API.v213, () => + return new VersionDependentRegistration(client, TypeScriptQuickFixProvider.minVersion, () => vscode.languages.registerCodeActionsProvider(selector, new TypeScriptQuickFixProvider(client, fileConfigurationManager, commandManager, diagnosticsManager, telemetryReporter), TypeScriptQuickFixProvider.metadata)); diff --git a/extensions/typescript-language-features/src/features/refactor.ts b/extensions/typescript-language-features/src/features/refactor.ts index d687fd61e6e..a3a7bb629e7 100644 --- a/extensions/typescript-language-features/src/features/refactor.ts +++ b/extensions/typescript-language-features/src/features/refactor.ts @@ -112,6 +112,8 @@ class SelectRefactorCommand implements Command { } class TypeScriptRefactorProvider implements vscode.CodeActionProvider { + public static readonly minVersion = API.v240; + private static readonly extractFunctionKind = vscode.CodeActionKind.RefactorExtract.append('function'); private static readonly extractConstantKind = vscode.CodeActionKind.RefactorExtract.append('constant'); private static readonly moveKind = vscode.CodeActionKind.Refactor.append('move'); @@ -236,7 +238,7 @@ export function register( commandManager: CommandManager, telemetryReporter: TelemetryReporter, ) { - return new VersionDependentRegistration(client, API.v240, () => { + return new VersionDependentRegistration(client, TypeScriptRefactorProvider.minVersion, () => { return vscode.languages.registerCodeActionsProvider(selector, new TypeScriptRefactorProvider(client, formattingOptionsManager, commandManager, telemetryReporter), TypeScriptRefactorProvider.metadata); diff --git a/extensions/typescript-language-features/src/features/referencesCodeLens.ts b/extensions/typescript-language-features/src/features/referencesCodeLens.ts index 7c256e3064f..ff09a9a4346 100644 --- a/extensions/typescript-language-features/src/features/referencesCodeLens.ts +++ b/extensions/typescript-language-features/src/features/referencesCodeLens.ts @@ -17,6 +17,7 @@ import { CachedResponse } from '../tsServer/cachedResponse'; const localize = nls.loadMessageBundle(); class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider { + public static readonly minVersion = API.v206; public async resolveCodeLens(inputCodeLens: vscode.CodeLens, token: vscode.CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; @@ -98,7 +99,7 @@ export function register( client: ITypeScriptServiceClient, cachedResponse: CachedResponse, ) { - return new VersionDependentRegistration(client, API.v206, () => + return new VersionDependentRegistration(client, TypeScriptReferencesCodeLensProvider.minVersion, () => new ConfigurationDependentRegistration(modeId, 'referencesCodeLens.enabled', () => { return vscode.languages.registerCodeLensProvider(selector, new TypeScriptReferencesCodeLensProvider(client, cachedResponse)); diff --git a/extensions/typescript-language-features/src/features/smartSelect.ts b/extensions/typescript-language-features/src/features/smartSelect.ts new file mode 100644 index 00000000000..a9a0370bee9 --- /dev/null +++ b/extensions/typescript-language-features/src/features/smartSelect.ts @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import * as Proto from '../protocol'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import API from '../utils/api'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; +import * as typeConverters from '../utils/typeConverters'; + +class SmartSelection implements vscode.SelectionRangeProvider { + public static readonly minVersion = API.v350; + + public constructor( + private readonly client: ITypeScriptServiceClient + ) { } + + public async provideSelectionRanges( + document: vscode.TextDocument, + positions: vscode.Position[], + token: vscode.CancellationToken, + ): Promise { + const file = this.client.toOpenedFilePath(document); + if (!file) { + return undefined; + } + + const args: Proto.FileRequestArgs & { locations: Proto.Location[] } = { + file, + locations: positions.map(typeConverters.Position.toLocation) + }; + const response = await this.client.execute('selectionRange', args, token); + if (response.type !== 'response' || !response.body) { + return undefined; + } + return response.body.map(SmartSelection.convertSelectionRange); + } + + private static convertSelectionRange( + selectionRange: Proto.SelectionRange + ): vscode.SelectionRange { + return new vscode.SelectionRange( + typeConverters.Range.fromTextSpan(selectionRange.textSpan), + selectionRange.parent ? SmartSelection.convertSelectionRange(selectionRange.parent) : undefined, + ); + } +} + +export function register( + selector: vscode.DocumentSelector, + client: ITypeScriptServiceClient, +) { + return new VersionDependentRegistration(client, SmartSelection.minVersion, () => + vscode.languages.registerSelectionRangeProvider(selector, new SmartSelection(client))); +} \ No newline at end of file diff --git a/extensions/typescript-language-features/src/features/tagClosing.ts b/extensions/typescript-language-features/src/features/tagClosing.ts index 34ddd2c0285..c8db74597e5 100644 --- a/extensions/typescript-language-features/src/features/tagClosing.ts +++ b/extensions/typescript-language-features/src/features/tagClosing.ts @@ -12,6 +12,7 @@ import { Disposable } from '../utils/dispose'; import * as typeConverters from '../utils/typeConverters'; class TagClosing extends Disposable { + public static readonly minVersion = API.v300; private _disposed = false; private _timeout: NodeJS.Timer | undefined = undefined; @@ -167,7 +168,7 @@ export function register( modeId: string, client: ITypeScriptServiceClient, ) { - return new VersionDependentRegistration(client, API.v300, () => + return new VersionDependentRegistration(client, TagClosing.minVersion, () => new ConfigurationDependentRegistration(modeId, 'autoClosingTags', () => new ActiveDocumentDependentRegistration(selector, () => new TagClosing(client)))); diff --git a/extensions/typescript-language-features/src/features/typeDefinitions.ts b/extensions/typescript-language-features/src/features/typeDefinitions.ts index 45d89aeaedd..86510f65189 100644 --- a/extensions/typescript-language-features/src/features/typeDefinitions.ts +++ b/extensions/typescript-language-features/src/features/typeDefinitions.ts @@ -10,6 +10,8 @@ import { VersionDependentRegistration } from '../utils/dependentRegistration'; import DefinitionProviderBase from './definitionProviderBase'; export default class TypeScriptTypeDefinitionProvider extends DefinitionProviderBase implements vscode.TypeDefinitionProvider { + public static readonly minVersion = API.v213; + public provideTypeDefinition(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { return this.getSymbolLocations('typeDefinition', document, position, token); } @@ -19,7 +21,7 @@ export function register( selector: vscode.DocumentSelector, client: ITypeScriptServiceClient, ) { - return new VersionDependentRegistration(client, API.v213, () => { + return new VersionDependentRegistration(client, TypeScriptTypeDefinitionProvider.minVersion, () => { return vscode.languages.registerTypeDefinitionProvider(selector, new TypeScriptTypeDefinitionProvider(client)); }); diff --git a/extensions/typescript-language-features/src/features/updatePathsOnRename.ts b/extensions/typescript-language-features/src/features/updatePathsOnRename.ts index 18c58e73df3..c4c2e9ca135 100644 --- a/extensions/typescript-language-features/src/features/updatePathsOnRename.ts +++ b/extensions/typescript-language-features/src/features/updatePathsOnRename.ts @@ -40,6 +40,8 @@ enum UpdateImportsOnFileMoveSetting { } class UpdateImportsOnFileRenameHandler extends Disposable { + public static minVersion = API.v300; + public constructor( private readonly client: ITypeScriptServiceClient, private readonly fileConfigurationManager: FileConfigurationManager, @@ -233,6 +235,6 @@ export function register( fileConfigurationManager: FileConfigurationManager, handles: (uri: vscode.Uri) => Promise, ) { - return new VersionDependentRegistration(client, API.v300, () => + return new VersionDependentRegistration(client, UpdateImportsOnFileRenameHandler.minVersion, () => new UpdateImportsOnFileRenameHandler(client, fileConfigurationManager, handles)); } \ No newline at end of file diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index 84dbb8e946d..4210ba2ba20 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -55,27 +55,30 @@ export default class LanguageProvider extends Disposable { const cachedResponse = new CachedResponse(); - this._register((await import('./features/completions')).register(selector, this.description.id, this.client, this.typingsStatus, this.fileConfigurationManager, this.commandManager, this.onCompletionAccepted)); - this._register((await import('./features/definitions')).register(selector, this.client)); - this._register((await import('./features/directiveCommentCompletions')).register(selector, this.client)); - this._register((await import('./features/documentHighlight')).register(selector, this.client)); - this._register((await import('./features/documentSymbol')).register(selector, this.client, cachedResponse)); - this._register((await import('./features/folding')).register(selector, this.client)); - this._register((await import('./features/formatting')).register(selector, this.description.id, this.client, this.fileConfigurationManager)); - this._register((await import('./features/hover')).register(selector, this.client)); - this._register((await import('./features/implementations')).register(selector, this.client)); - this._register((await import('./features/implementationsCodeLens')).register(selector, this.description.id, this.client, cachedResponse)); - this._register((await import('./features/jsDocCompletions')).register(selector, this.description.id, this.client)); - this._register((await import('./features/organizeImports')).register(selector, this.client, this.commandManager, this.fileConfigurationManager, this.telemetryReporter)); - this._register((await import('./features/quickFix')).register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.client.diagnosticsManager, this.telemetryReporter)); - this._register((await import('./features/fixAll')).register(selector, this.client, this.fileConfigurationManager, this.client.diagnosticsManager)); - this._register((await import('./features/refactor')).register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.telemetryReporter)); - this._register((await import('./features/references')).register(selector, this.client)); - this._register((await import('./features/referencesCodeLens')).register(selector, this.description.id, this.client, cachedResponse)); - this._register((await import('./features/rename')).register(selector, this.client, this.fileConfigurationManager)); - this._register((await import('./features/signatureHelp')).register(selector, this.client)); - this._register((await import('./features/tagClosing')).register(selector, this.description.id, this.client)); - this._register((await import('./features/typeDefinitions')).register(selector, this.client)); + await Promise.all([ + import('./features/completions').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.typingsStatus, this.fileConfigurationManager, this.commandManager, this.telemetryReporter, this.onCompletionAccepted))), + import('./features/definitions').then(provider => this._register(provider.register(selector, this.client))), + import('./features/directiveCommentCompletions').then(provider => this._register(provider.register(selector, this.client))), + import('./features/documentHighlight').then(provider => this._register(provider.register(selector, this.client))), + import('./features/documentSymbol').then(provider => this._register(provider.register(selector, this.client, cachedResponse))), + import('./features/folding').then(provider => this._register(provider.register(selector, this.client))), + import('./features/formatting').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.fileConfigurationManager))), + import('./features/hover').then(provider => this._register(provider.register(selector, this.client))), + import('./features/implementations').then(provider => this._register(provider.register(selector, this.client))), + import('./features/implementationsCodeLens').then(provider => this._register(provider.register(selector, this.description.id, this.client, cachedResponse))), + import('./features/jsDocCompletions').then(provider => this._register(provider.register(selector, this.description.id, this.client))), + import('./features/organizeImports').then(provider => this._register(provider.register(selector, this.client, this.commandManager, this.fileConfigurationManager, this.telemetryReporter))), + import('./features/quickFix').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.client.diagnosticsManager, this.telemetryReporter))), + import('./features/fixAll').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.client.diagnosticsManager))), + import('./features/refactor').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.telemetryReporter))), + import('./features/references').then(provider => this._register(provider.register(selector, this.client))), + import('./features/referencesCodeLens').then(provider => this._register(provider.register(selector, this.description.id, this.client, cachedResponse))), + import('./features/rename').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager))), + import('./features/smartSelect').then(provider => this._register(provider.register(selector, this.client))), + import('./features/signatureHelp').then(provider => this._register(provider.register(selector, this.client))), + import('./features/tagClosing').then(provider => this._register(provider.register(selector, this.description.id, this.client))), + import('./features/typeDefinitions').then(provider => this._register(provider.register(selector, this.client))), + ]); } private configurationChanged(): void { diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 277d6e3f47c..32ed3a60060 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -11,6 +11,17 @@ import { TypeScriptServiceConfiguration } from './utils/configuration'; import Logger from './utils/logger'; import { PluginManager } from './utils/plugins'; +declare module './protocol' { + interface SelectionRange { + textSpan: Proto.TextSpan; + parent?: SelectionRange; + } + + interface SelectionRangeResponse extends Proto.Response { + body?: ReadonlyArray; + } +} + export namespace ServerResponse { export class Cancelled { @@ -54,6 +65,7 @@ export interface TypeScriptRequestTypes { 'quickinfo': [Proto.FileLocationRequestArgs, Proto.QuickInfoResponse]; 'references': [Proto.FileLocationRequestArgs, Proto.ReferencesResponse]; 'rename': [Proto.RenameRequestArgs, Proto.RenameResponse]; + 'selectionRange': [Proto.FileRequestArgs & { locations: Proto.Location[] }, Proto.SelectionRangeResponse]; 'signatureHelp': [Proto.SignatureHelpRequestArgs, Proto.SignatureHelpResponse]; 'typeDefinition': [Proto.FileLocationRequestArgs, Proto.TypeDefinitionResponse]; } diff --git a/extensions/typescript-language-features/src/utils/api.ts b/extensions/typescript-language-features/src/utils/api.ts index a48a9f78f1f..9dcd05013db 100644 --- a/extensions/typescript-language-features/src/utils/api.ts +++ b/extensions/typescript-language-features/src/utils/api.ts @@ -36,6 +36,7 @@ export default class API { public static readonly v330 = API.fromSimpleString('3.3.0'); public static readonly v333 = API.fromSimpleString('3.3.3'); public static readonly v340 = API.fromSimpleString('3.4.0'); + public static readonly v350 = API.fromSimpleString('3.5.0'); public static fromVersionString(versionString: string): API { diff --git a/package.json b/package.json index af7e321e6f2..2fae932a2b5 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "vscode-ripgrep": "^1.2.5", "vscode-sqlite3": "4.0.7", "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.13.0-beta2", + "vscode-xterm": "3.13.0-beta3", "yauzl": "^2.9.1", "yazl": "^2.4.3" }, @@ -85,12 +85,12 @@ "gulp-atom-electron": "^1.20.0", "gulp-azure-storage": "^0.10.0", "gulp-buffer": "0.0.2", - "gulp-gunzip": "^1.0.0", "gulp-concat": "^2.6.1", "gulp-cssnano": "^2.1.3", "gulp-eslint": "^5.0.0", "gulp-filter": "^5.1.0", "gulp-flatmap": "^1.0.2", + "gulp-gunzip": "^1.0.0", "gulp-json-editor": "^2.5.0", "gulp-plumber": "^1.2.0", "gulp-remote-src": "^0.4.4", @@ -146,10 +146,10 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "optionalDependencies": { - "vscode-windows-registry": "1.0.1", "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" } -} \ No newline at end of file +} diff --git a/src/tsconfig.monaco.json b/src/tsconfig.monaco.json index 1303af547f4..afcbcaff39c 100644 --- a/src/tsconfig.monaco.json +++ b/src/tsconfig.monaco.json @@ -1,18 +1,16 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { "noEmit": true, + "types": [], + "paths": {}, "module": "amd", "moduleResolution": "classic", - "noImplicitAny": false, "removeComments": false, "preserveConstEnums": true, "target": "es5", "sourceMap": false, - "experimentalDecorators": true, "declaration": true, - "noImplicitReturns": true, - "baseUrl": ".", - "types": [] }, "include": [ "typings/require.d.ts", diff --git a/src/vs/base/browser/dnd.ts b/src/vs/base/browser/dnd.ts index 76fa2957325..1a5d28e802e 100644 --- a/src/vs/base/browser/dnd.ts +++ b/src/vs/base/browser/dnd.ts @@ -68,7 +68,7 @@ export const DataTransfers = { FILES: 'Files', /** - * Typicaly transfer type for copy/paste transfers. + * Typically transfer type for copy/paste transfers. */ TEXT: 'text/plain' }; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index ccce65e591c..85ce189ee98 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -467,28 +467,6 @@ export function getComputedStyle(el: HTMLElement): CSSStyleDeclaration { return document.defaultView!.getComputedStyle(el, null); } -// Adapted from WinJS -// Converts a CSS positioning string for the specified element to pixels. -const convertToPixels: (element: HTMLElement, value: string) => number = (function () { - return function (element: HTMLElement, value: string): number { - return parseFloat(value) || 0; - }; -})(); - -function getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number { - let computedStyle: CSSStyleDeclaration = getComputedStyle(element); - let value = '0'; - if (computedStyle) { - if (computedStyle.getPropertyValue) { - value = computedStyle.getPropertyValue(cssPropertyName); - } else { - // IE8 - value = (computedStyle).getAttribute(jsPropertyName); - } - } - return convertToPixels(element, value); -} - export function getClientArea(element: HTMLElement): Dimension { // Try with DOM clientWidth / clientHeight @@ -514,48 +492,66 @@ export function getClientArea(element: HTMLElement): Dimension { throw new Error('Unable to figure out browser width and height'); } -const sizeUtils = { +class SizeUtils { + // Adapted from WinJS + // Converts a CSS positioning string for the specified element to pixels. + private static convertToPixels(element: HTMLElement, value: string): number { + return parseFloat(value) || 0; + } - getBorderLeftWidth: function (element: HTMLElement): number { - return getDimension(element, 'border-left-width', 'borderLeftWidth'); - }, - getBorderRightWidth: function (element: HTMLElement): number { - return getDimension(element, 'border-right-width', 'borderRightWidth'); - }, - getBorderTopWidth: function (element: HTMLElement): number { - return getDimension(element, 'border-top-width', 'borderTopWidth'); - }, - getBorderBottomWidth: function (element: HTMLElement): number { - return getDimension(element, 'border-bottom-width', 'borderBottomWidth'); - }, + private static getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number { + let computedStyle: CSSStyleDeclaration = getComputedStyle(element); + let value = '0'; + if (computedStyle) { + if (computedStyle.getPropertyValue) { + value = computedStyle.getPropertyValue(cssPropertyName); + } else { + // IE8 + value = (computedStyle).getAttribute(jsPropertyName); + } + } + return SizeUtils.convertToPixels(element, value); + } - getPaddingLeft: function (element: HTMLElement): number { - return getDimension(element, 'padding-left', 'paddingLeft'); - }, - getPaddingRight: function (element: HTMLElement): number { - return getDimension(element, 'padding-right', 'paddingRight'); - }, - getPaddingTop: function (element: HTMLElement): number { - return getDimension(element, 'padding-top', 'paddingTop'); - }, - getPaddingBottom: function (element: HTMLElement): number { - return getDimension(element, 'padding-bottom', 'paddingBottom'); - }, + static getBorderLeftWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-left-width', 'borderLeftWidth'); + } + static getBorderRightWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-right-width', 'borderRightWidth'); + } + static getBorderTopWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-top-width', 'borderTopWidth'); + } + static getBorderBottomWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-bottom-width', 'borderBottomWidth'); + } - getMarginLeft: function (element: HTMLElement): number { - return getDimension(element, 'margin-left', 'marginLeft'); - }, - getMarginTop: function (element: HTMLElement): number { - return getDimension(element, 'margin-top', 'marginTop'); - }, - getMarginRight: function (element: HTMLElement): number { - return getDimension(element, 'margin-right', 'marginRight'); - }, - getMarginBottom: function (element: HTMLElement): number { - return getDimension(element, 'margin-bottom', 'marginBottom'); - }, - __commaSentinel: false -}; + static getPaddingLeft(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-left', 'paddingLeft'); + } + static getPaddingRight(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-right', 'paddingRight'); + } + static getPaddingTop(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-top', 'paddingTop'); + } + static getPaddingBottom(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-bottom', 'paddingBottom'); + } + + static getMarginLeft(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-left', 'marginLeft'); + } + static getMarginTop(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-top', 'marginTop'); + } + static getMarginRight(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-right', 'marginRight'); + } + static getMarginBottom(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-bottom', 'marginBottom'); + } +} // ---------------------------------------------------------------------------------------- // Position & Dimension @@ -594,8 +590,8 @@ export function getTopLeftOffset(element: HTMLElement): { left: number; top: num } if (element === offsetParent) { - left += sizeUtils.getBorderLeftWidth(element); - top += sizeUtils.getBorderTopWidth(element); + left += SizeUtils.getBorderLeftWidth(element); + top += SizeUtils.getBorderTopWidth(element); top += element.offsetTop; left += element.offsetLeft; offsetParent = element.offsetParent; @@ -686,33 +682,33 @@ export const StandardWindow: IStandardWindow = new class implements IStandardWin // Adapted from WinJS // Gets the width of the element, including margins. export function getTotalWidth(element: HTMLElement): number { - let margin = sizeUtils.getMarginLeft(element) + sizeUtils.getMarginRight(element); + let margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element); return element.offsetWidth + margin; } export function getContentWidth(element: HTMLElement): number { - let border = sizeUtils.getBorderLeftWidth(element) + sizeUtils.getBorderRightWidth(element); - let padding = sizeUtils.getPaddingLeft(element) + sizeUtils.getPaddingRight(element); + let border = SizeUtils.getBorderLeftWidth(element) + SizeUtils.getBorderRightWidth(element); + let padding = SizeUtils.getPaddingLeft(element) + SizeUtils.getPaddingRight(element); return element.offsetWidth - border - padding; } export function getTotalScrollWidth(element: HTMLElement): number { - let margin = sizeUtils.getMarginLeft(element) + sizeUtils.getMarginRight(element); + let margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element); return element.scrollWidth + margin; } // Adapted from WinJS // Gets the height of the content of the specified element. The content height does not include borders or padding. export function getContentHeight(element: HTMLElement): number { - let border = sizeUtils.getBorderTopWidth(element) + sizeUtils.getBorderBottomWidth(element); - let padding = sizeUtils.getPaddingTop(element) + sizeUtils.getPaddingBottom(element); + let border = SizeUtils.getBorderTopWidth(element) + SizeUtils.getBorderBottomWidth(element); + let padding = SizeUtils.getPaddingTop(element) + SizeUtils.getPaddingBottom(element); return element.offsetHeight - border - padding; } // Adapted from WinJS // Gets the height of the element, including its margins. export function getTotalHeight(element: HTMLElement): number { - let margin = sizeUtils.getMarginTop(element) + sizeUtils.getMarginBottom(element); + let margin = SizeUtils.getMarginTop(element) + SizeUtils.getMarginBottom(element); return element.offsetHeight + margin; } diff --git a/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts index 77f94de61f8..2499d715f8f 100644 --- a/src/vs/base/browser/touch.ts +++ b/src/vs/base/browser/touch.ts @@ -214,10 +214,10 @@ export class Gesture extends Disposable { } } - private newGestureEvent(type: string, intialTarget?: EventTarget): GestureEvent { + private newGestureEvent(type: string, initialTarget?: EventTarget): GestureEvent { let event = (document.createEvent('CustomEvent')); event.initEvent(type, false, true); - event.initialTarget = intialTarget; + event.initialTarget = initialTarget; return event; } diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index 9910bf95f55..28658f3ee60 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -126,7 +126,7 @@ export class BreadcrumbsWidget { this._pendingLayout.dispose(); } if (dim) { - // only meaure + // only measure this._pendingLayout = this._updateDimensions(dim); } else { this._pendingLayout = this._updateScrollbar(); diff --git a/src/vs/base/browser/ui/dialog/dialog.css b/src/vs/base/browser/ui/dialog/dialog.css index 8f5d835974d..f772e57fcc5 100644 --- a/src/vs/base/browser/ui/dialog/dialog.css +++ b/src/vs/base/browser/ui/dialog/dialog.css @@ -15,6 +15,10 @@ align-items: center; } +.monaco-workbench .dialog-modal-block.dimmed { + background: rgba(0, 0, 0, 0.3); +} + /** Dialog: Container */ .monaco-workbench .dialog-box { display: flex; @@ -66,6 +70,10 @@ background-repeat: no-repeat; } +.vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { + background-image: url('pending.svg'); +} + .vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info { background-image: url('info.svg'); } @@ -78,6 +86,10 @@ background-image: url('error.svg'); } +.vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { + background-image: url('pending-dark.svg'); +} + .vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info, .hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info { background-image: url('info-inverse.svg'); @@ -93,6 +105,14 @@ background-image: url('error-inverse.svg'); } +.hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { + background-image: url('pending-hc.svg'); +} + +.monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { + background-size: 30px; +} + /** Dialog: Message Container */ .monaco-workbench .dialog-box .dialog-message-row .dialog-message-container { display: flex; diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 0ee6b1f6555..2116fb99164 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -19,7 +19,7 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels'; export interface IDialogOptions { cancelId?: number; detail?: string; - type?: 'none' | 'info' | 'error' | 'question' | 'warning'; + type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending'; } export interface IDialogStyles extends IButtonStyles { @@ -40,7 +40,7 @@ export class Dialog extends Disposable { constructor(private container: HTMLElement, private message: string, private buttons: string[], private options: IDialogOptions) { super(); - this.modal = this.container.appendChild($('.dialog-modal-block')); + this.modal = this.container.appendChild($(`.dialog-modal-block${options.type === 'pending' ? '.dimmed' : ''}`)); this.element = this.modal.appendChild($('.dialog-box')); hide(this.element); @@ -129,6 +129,9 @@ export class Dialog extends Disposable { case 'warning': addClass(this.iconElement, 'icon-warning'); break; + case 'pending': + addClass(this.iconElement, 'icon-pending'); + break; case 'none': case 'info': case 'question': diff --git a/src/vs/base/browser/ui/dialog/pending-dark.svg b/src/vs/base/browser/ui/dialog/pending-dark.svg new file mode 100644 index 00000000000..bbf6e8d84cf --- /dev/null +++ b/src/vs/base/browser/ui/dialog/pending-dark.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + diff --git a/src/vs/base/browser/ui/dialog/pending-hc.svg b/src/vs/base/browser/ui/dialog/pending-hc.svg new file mode 100644 index 00000000000..4d0b2a10c79 --- /dev/null +++ b/src/vs/base/browser/ui/dialog/pending-hc.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + diff --git a/src/vs/base/browser/ui/dialog/pending.svg b/src/vs/base/browser/ui/dialog/pending.svg new file mode 100644 index 00000000000..596cfdd60cd --- /dev/null +++ b/src/vs/base/browser/ui/dialog/pending.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 0869c52c0d2..5babdbf0d72 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -502,7 +502,7 @@ function isMouseRightClick(event: UIEvent): boolean { return event instanceof MouseEvent && event.button === 2; } -const DefaultMultipleSelectionContoller = { +const DefaultMultipleSelectionController = { isSelectionSingleChangeEvent, isSelectionRangeChangeEvent }; @@ -529,7 +529,7 @@ export class MouseController implements IDisposable { this.multipleSelectionSupport = !(list.options.multipleSelectionSupport === false); if (this.multipleSelectionSupport) { - this.multipleSelectionController = list.options.multipleSelectionController || DefaultMultipleSelectionContoller; + this.multipleSelectionController = list.options.multipleSelectionController || DefaultMultipleSelectionController; } this.openController = list.options.openController || DefaultOpenController; @@ -909,7 +909,7 @@ function getContiguousRangeContaining(range: number[], value: number): number[] /** * Given two sorted collections of numbers, returns the intersection - * betweem them (OR). + * between them (OR). */ function disjunction(one: number[], other: number[]): number[] { const result: number[] = []; diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css index d24cc0b5258..d583733048e 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css @@ -1,7 +1,7 @@ @font-face { font-family: "octicons"; - src: url("./octicons.ttf?4cd2299755e93a2430ba5703f4476584") format("truetype"), -url("./octicons.svg?4cd2299755e93a2430ba5703f4476584#octicons") format("svg"); + src: url("./octicons.ttf?91284a5a76ea88faeb754359b7f7cd03") format("truetype"), +url("./octicons.svg?91284a5a76ea88faeb754359b7f7cd03#octicons") format("svg"); } .octicon, .mega-octicon { @@ -240,4 +240,5 @@ url("./octicons.svg?4cd2299755e93a2430ba5703f4476584#octicons") format("svg"); .octicon-fold-up:before { content: "\f105" } .octicon-github-action:before { content: "\f106" } .octicon-play:before { content: "\f107" } -.octicon-request-changes:before { content: "\f108" } +.octicon-remote:before { content: "\f108" } +.octicon-request-changes:before { content: "\f109" } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg index 4581795255c..af839609786 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg @@ -421,6 +421,9 @@ + @@ -446,7 +449,7 @@ unicode="" horiz-adv-x="1000" d=" M437.5 320H562.5V195H437.5z M437.5 632.5H562.5V382.5H437.5z M937.5 757.5H62.5C25 757.5 0 732.5 0 695V132.5C0 95 25 70 62.5 70H187.5V-180L437.5 70H937.5C975 70 1000 95 1000 132.5V695C1000 732.5 975 757.5 937.5 757.5zM937.5 132.5H406.25L250 -23.75V132.5H62.5V695H937.5z" /> + horiz-adv-x="1000" d=" M998.75 330.625L938.125 702.5C927.5 788.75 820.625 820 750 820H355.625C343.125 820 331.8750000000001 816.875 322.5 811.25L232.5 757.5H125C58.75 757.5 0 698.75 0 632.5V382.5C0 316.25 58.75 256.25 125 257.5H250C306.875 257.5 336.875 229.375 399.3750000000001 160.625C456.2500000000001 98.125 454.3750000000001 48.1249999999999 438.7500000000001 -43.75C433.75 -75 442.5 -106.25 465 -132.5C489.375 -161.875 526.25 -180 562.5 -180C676.875 -180 750 51.875 750 133.125L748.75 194.375H876.25C948.75 194.375 998.1249999999998 244.3750000000001 1000 317.5000000000001C1000 324.3750000000001 998.75 330.6250000000001 998.75 330.6250000000001zM875.625 256.25H751.25C707.5 256.25 686.875 238.7500000000001 686.875 195.625L688.75 131.25C688.75 51.875 615.625 -118.75 563.75 -118.75C532.5 -118.75 496.2499999999999 -87.5 501.25 -56.25C516.875 42.5 522.5 117.5 445.625 202.5000000000001C381.875 273.125 335 320 250 320V695L354.375 757.5H750C795.625 757.5 871.875 738.125 875 695L876.25 693.75L938.75 318.75C936.875 278.75 914.9999999999998 256.25 876.25 256.25H875.625z" /> + horiz-adv-x="1000" d=" M998.75 309.375L938.125 -62.5000000000001C927.5 -148.75 820.625 -180 750 -180H355.625C343.125 -180 331.8750000000001 -176.875 322.5 -171.25L232.5 -117.5H125C58.75 -117.5 0 -58.75 0 7.5V257.5C0 323.7500000000001 58.75 383.75 125 382.5H250C306.875 382.5 336.875 410.625 399.3750000000001 479.375C456.2500000000001 541.875 454.3750000000001 591.875 438.7500000000001 683.75C433.75 715 442.5 746.25 465 772.5C489.375 801.875 526.25 820 562.5 820C676.875 820 750 588.125 750 506.875L748.75 445.625H876.25C948.75 445.625 998.1249999999998 395.625 1000 322.5C1000 315.625 998.75 309.375 998.75 309.375zM875.625 383.75H751.25C707.5 383.75 686.875 401.25 686.875 444.375L688.75 508.75C688.75 588.125 615.625 758.75 563.75 758.75C532.5 758.75 496.2499999999999 727.5 501.25 696.25C516.875 597.5 522.5 522.5 445.625 437.5C381.875 366.875 335 320 250 320V-55L354.375 -117.5H750C795.625 -117.5 871.875 -98.125 875 -55L876.25 -53.75L938.75 321.25C936.875 361.25 914.9999999999998 383.75 876.25 383.75H875.625z" /> @@ -546,10 +549,10 @@ horiz-adv-x="1000" d=" M750 318.75C750 250.625 721.875 188.125 676.875 141.875L635 183.75C669.375 218.75 690.625 265.625 690.625 318.75C690.625 371.875 669.375 419.3750000000001 635 453.7500000000001L676.875 495.6250000000001A249.375 249.375 0 0 0 750 318.75zM482.5 677.5L250 445H125C90.625 445 62.5 416.875 62.5 382.5V257.5C62.5 223.125 90.625 195 125 195H250L482.5000000000001 -37.5C511.8750000000001 -66.8750000000001 562.5 -46.2500000000001 562.5 -4.3750000000001V644.375C562.5 686.25 511.8749999999999 706.875 482.5 677.5zM853.75 672.5L811.875 630.625A437.24999999999994 437.24999999999994 0 0 0 940.625 319.375C940.625 198.125 891.8750000000001 88.125 811.875 8.125L853.75 -33.75A498.31249999999994 498.31249999999994 0 0 1 1000 320C1000 458.7500000000001 944.375 583.75 853.75 673.75V672.5zM765.625 584.375L722.5 542.5A315.62499999999994 315.62499999999994 0 0 0 815.0000000000001 318.75C815.0000000000001 231.875 780 152.5 722.5 96.25L765.625 54.375A373.18750000000006 373.18750000000006 0 0 1 875 318.75C875 421.8750000000001 833.125 516.25 765.625 584.375z" /> + horiz-adv-x="1000" d=" M979.375 378.375L911.875 462.125A93.75 93.75 0 0 0 892.5625 510.2500000000001L880.6875000000001 616.375A94.375 94.375 0 0 1 797.625 699.5L691.4375 711.375C672.6875 713.25 656.4375 721.3125 642.6875000000001 731.9375L559.0625 799.375A94 94 0 0 1 441.6875 799.375L357.9375 731.875A93.75 93.75 0 0 0 309.8125000000001 712.5L203.6875000000001 700.625C159.9375000000001 695.625 125.5625000000001 661.25 120.5625000000001 617.5625L108.6875 511.375C106.8125 492.625 98.75 476.3750000000001 88.1250000000001 462.625L20.625 379.0625A94 94 0 0 1 20.625 261.6875L88.125 177.9375C98.75 164.1875 105.625 147.9375 107.5 129.8125L119.375 23.6875C124.375 -20.0624999999999 158.75 -54.4375 202.4375 -59.4375L308.625 -71.3125C327.375 -73.1874999999999 343.625 -81.25 357.375 -91.875L441.0625 -159.375C475.4375 -186.8124999999999 524.1250000000001 -186.8124999999999 558.4375 -159.375L642.1875 -91.875C655.9375000000001 -81.25 672.1875 -74.375 690.3125 -72.5L796.4375 -60.625C840.1875 -55.625 874.5625 -21.2499999999999 879.5625 22.4375L891.4375 128.625C893.3125 147.3750000000001 901.375 163.6250000000001 912 177.375L979.5 261.0625A94 94 0 0 1 979.5 378.4375000000001zM562.5 101.25C562.5 83.75 548.75 70 531.25 70H468.75C451.875 70 437.5 83.75 437.5 101.25V163.75C437.5 181.25 451.875 195 468.75 195H531.25C548.75 195 562.5 181.25 562.5 163.75V101.25zM660 406.875C656.25 396.25 649.375 386.25 641.25 377.5C633.1249999999999 367.5 632.5 365.625 620.625 353.75C610.625 343.125 601.25 335 588.125 325.625C581.25 320 575.625 313.75 570.625 308.75C565.625 303.75 561.875 298.125 558.7500000000001 291.875C555.625 285.6250000000001 553.7500000000001 280.0000000000001 551.8750000000001 273.125C550.0000000000001 266.25 550.0000000000001 265 550.0000000000001 257.5H445.625C445.625 271.25 445.625 276.875 447.5 287.5C449.375 299.375 452.5 310 456.25 320C459.9999999999999 328.75 464.9999999999999 337.5 471.875 346.25C478.75 354.375 486.25 361.875 497.5 370C514.375 381.875 520 388.75 527.5 402.5C534.9999999999999 416.25 539.9999999999999 426.25 539.9999999999999 439.375C539.9999999999999 456.25 536.2499999999999 467.5 527.5 475.625C519.3749999999999 483.75 508.1249999999999 487.5000000000001 491.2499999999999 487.5000000000001C485.625 487.5000000000001 479.3749999999999 486.2500000000001 472.5 484.3750000000001C465.6249999999999 482.5000000000001 461.875 478.7500000000001 456.875 474.3750000000001C451.8749999999999 470 448.125 467.5 444.375 461.8750000000001A25.624999999999996 25.624999999999996 0 0 1 438.75 444.375H313.75C313.75 468.125 321.875 479.3750000000001 330.625 496.25C340.625 513.125 353.125 527.5 368.75 538.125C384.375 548.75 403.125 556.875 423.75 561.875C444.375 566.875 467.4999999999999 570 491.8749999999999 570C519.3749999999999 570 543.75 566.875 565 561.875C586.2499999999999 556.25 604.375 548.125 620 537.5C634.375 526.875 645.625 513.75 654.375 498.1250000000001C662.5000000000001 482.5000000000001 666.25 463.7500000000001 666.25 443.1250000000001C666.25 429.3750000000001 666.25 416.8750000000001 661.25 406.2500000000001L660 406.8750000000001z" /> + horiz-adv-x="1000" d=" M979.375 378.375L911.875 462.125A93.75 93.75 0 0 0 892.5625 510.2500000000001L880.6875000000001 616.375A94.375 94.375 0 0 1 797.625 699.5L691.4375 711.375C672.6875 713.25 656.4375 721.3125 642.6875000000001 731.9375L559.0625 799.375A94 94 0 0 1 441.6875 799.375L357.9375 731.875A93.75 93.75 0 0 0 309.8125000000001 712.5L203.6875000000001 700.625C159.9375000000001 695.625 125.5625000000001 661.25 120.5625000000001 617.5625L108.6875 511.375C106.8125 492.625 98.75 476.3750000000001 88.1250000000001 462.625L20.625 379.0625A94 94 0 0 1 20.625 261.6875L88.125 177.9375C98.75 164.1875 105.625 147.9375 107.5 129.8125L119.375 23.6875C124.375 -20.0624999999999 158.75 -54.4375 202.4375 -59.4375L308.625 -71.3125C327.375 -73.1874999999999 343.625 -81.25 357.375 -91.875L441.0625 -159.375C475.4375 -186.8124999999999 524.1250000000001 -186.8124999999999 558.4375 -159.375L642.1875 -91.875C655.9375000000001 -81.25 672.1875 -74.375 690.3125 -72.5L796.4375 -60.625C840.1875 -55.625 874.5625 -21.2499999999999 879.5625 22.4375L891.4375 128.625C893.3125 147.3750000000001 901.375 163.6250000000001 912 177.375L979.5 261.0625A94 94 0 0 1 979.5 378.4375000000001zM406.25 69.375L187.5 288.125L281.25 381.875L406.25 256.875L718.75 569.375L812.5 472.5L406.25 69.375z" /> diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf index 12b561cd47a..8c29d338308 100644 Binary files a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf and b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf differ diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index 9b31c847f70..fbf8d5dcd13 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -523,7 +523,7 @@ export class DomScrollableElement extends ScrollableElement { } public scanDomNode(): void { - // widh, scrollLeft, scrollWidth, height, scrollTop, scrollHeight + // width, scrollLeft, scrollWidth, height, scrollTop, scrollHeight this.setScrollDimensions({ width: this._element.clientWidth, scrollWidth: this._element.scrollWidth, diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 03bf0c095b8..cedb6fbd423 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -33,7 +33,7 @@ export const enum TreeVisibility { export interface ITreeFilterDataResult { /** - * Whether the node should be visibile. + * Whether the node should be visible. */ visibility: boolean | TreeVisibility; diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 79560531ae8..ec6497ef0b6 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -226,7 +226,7 @@ export class URI implements UriComponents { // ---- modify to new ------------------------- - public with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI { + with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI { if (!change) { return this; @@ -279,7 +279,7 @@ export class URI implements UriComponents { * * @param value A string which represents an URI (see `URI#toString`). */ - public static parse(value: string, _strict: boolean = false): URI { + static parse(value: string, _strict: boolean = false): URI { const match = _regexp.exec(value); if (!match) { return new _URI(_empty, _empty, _empty, _empty, _empty); @@ -315,7 +315,7 @@ export class URI implements UriComponents { * * @param path A file system path (see `URI#fsPath`) */ - public static file(path: string): URI { + static file(path: string): URI { let authority = _empty; @@ -342,7 +342,7 @@ export class URI implements UriComponents { return new _URI('file', authority, path, _empty, _empty); } - public static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { + static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { return new _URI( components.scheme, components.authority, @@ -365,15 +365,19 @@ export class URI implements UriComponents { * * @param skipEncoding Do not encode the result, default is `false` */ - public toString(skipEncoding: boolean = false): string { + toString(skipEncoding: boolean = false): string { return _asFormatted(this, skipEncoding); } - public toJSON(): object { + toJSON(): UriComponents { return this; } - static revive(data: UriComponents | any): URI { + static revive(data: UriComponents | URI): URI; + static revive(data: UriComponents | URI | undefined): URI | undefined; + static revive(data: UriComponents | URI | null): URI | null; + static revive(data: UriComponents | URI | undefined | null): URI | undefined | null; + static revive(data: UriComponents | URI | undefined | null): URI | undefined | null { if (!data) { return data; } else if (data instanceof URI) { @@ -415,7 +419,7 @@ class _URI extends URI { return this._fsPath; } - public toString(skipEncoding: boolean = false): string { + toString(skipEncoding: boolean = false): string { if (!skipEncoding) { if (!this._formatted) { this._formatted = _asFormatted(this, false); @@ -427,7 +431,7 @@ class _URI extends URI { } } - toJSON(): object { + toJSON(): UriComponents { const res = { $mid: 1 }; diff --git a/src/vs/base/node/ps.sh b/src/vs/base/node/ps.sh new file mode 100755 index 00000000000..4fe31039c5a --- /dev/null +++ b/src/vs/base/node/ps.sh @@ -0,0 +1,39 @@ +#!/bin/sh +PAGESIZE=`getconf PAGESIZE`; +TOTAL_MEMORY=`cat /proc/meminfo | head -n 1 | awk '{print $2}'`; + +# Mimic the output of ps -ax -o pid=,ppid=,pcpu=,pmem=,command= +# Read all numeric subdirectories in /proc +for pid in `cd /proc && ls -d [0-9]*` + do { + if [ -e /proc/$pid/stat ] + then + echo $pid; + + # ppid is the word at index 4 in the stat file for the process + awk '{print $4}' /proc/$pid/stat; + + # pcpu - calculation will be done later, this is a placeholder value + echo "0.0" + + # pmem - ratio of the process's working set size to total memory. + # use the page size to convert to bytes, total memory is in KB + # multiplied by 100 to get percentage, extra 10 to be able to move + # the decimal over by one place + RESIDENT_SET_SIZE=`awk '{print $24}' /proc/$pid/stat`; + PERCENT_MEMORY=$(((1000 * $PAGESIZE * $RESIDENT_SET_SIZE) / ($TOTAL_MEMORY * 1024))); + if [ $PERCENT_MEMORY -lt 10 ] + then + # replace the last character with 0. the last character + echo $PERCENT_MEMORY | sed 's/.$/0.&/'; #pmem + else + # insert . before the last character + echo $PERCENT_MEMORY | sed 's/.$/.&/'; + fi + + # cmdline + xargs -0 < /proc/$pid/cmdline; + fi + } | tr "\n" "\t"; # Replace newlines with tab so that all info for a process is shown on one line + echo; # But add new lines between processes +done diff --git a/src/vs/base/node/ps.ts b/src/vs/base/node/ps.ts index a3c32449255..55c3a73da57 100644 --- a/src/vs/base/node/ps.ts +++ b/src/vs/base/node/ps.ts @@ -14,6 +14,7 @@ export function listProcesses(rootPid: number): Promise { let rootItem: ProcessItem | undefined; const map = new Map(); + function addToTree(pid: number, ppid: number, cmd: string, load: number, mem: number) { const parent = map.get(ppid); @@ -162,66 +163,72 @@ export function listProcesses(rootPid: number): Promise { }, windowsProcessTree.ProcessDataFlag.CommandLine | windowsProcessTree.ProcessDataFlag.Memory); }); } else { // OS X & Linux + function calculateLinuxCpuUsage() { + // Flatten rootItem to get a list of all VSCode processes + let processes = [rootItem]; + const pids: number[] = []; + while (processes.length) { + const process = processes.shift(); + if (process) { + pids.push(process.pid); + if (process.children) { + processes = processes.concat(process.children); + } + } + } + + // The cpu usage value reported on Linux is the average over the process lifetime, + // recalculate the usage over a one second interval + // JSON.stringify is needed to escape spaces, https://github.com/nodejs/node/issues/6803 + let cmd = JSON.stringify(getPathFromAmdModule(require, 'vs/base/node/cpuUsage.sh')); + cmd += ' ' + pids.join(' '); + + exec(cmd, {}, (err, stdout, stderr) => { + if (err || stderr) { + reject(err || new Error(stderr.toString())); + } else { + const cpuUsage = stdout.toString().split('\n'); + for (let i = 0; i < pids.length; i++) { + const processInfo = map.get(pids[i])!; + processInfo.load = parseFloat(cpuUsage[i]); + } + + resolve(rootItem); + } + }); + } + exec('which ps', {}, (err, stdout, stderr) => { if (err || stderr) { - reject(err || new Error(stderr.toString())); + if (process.platform !== 'linux') { + reject(err || new Error(stderr.toString())); + } else { + const cmd = JSON.stringify(getPathFromAmdModule(require, 'vs/base/node/ps.sh')); + exec(cmd, {}, (err, stdout, stderr) => { + if (err || stderr) { + reject(err || new Error(stderr.toString())); + } else { + parsePsOutput(stdout, addToTree); + calculateLinuxCpuUsage(); + } + }); + } } else { const ps = stdout.toString().trim(); const args = '-ax -o pid=,ppid=,pcpu=,pmem=,command='; - const PID_CMD = /^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)\s+(.+)$/; // Set numeric locale to ensure '.' is used as the decimal separator exec(`${ps} ${args}`, { maxBuffer: 1000 * 1024, env: { LC_NUMERIC: 'en_US.UTF-8' } }, (err, stdout, stderr) => { - if (err || stderr) { reject(err || new Error(stderr.toString())); } else { - - const lines = stdout.toString().split('\n'); - for (const line of lines) { - const matches = PID_CMD.exec(line.trim()); - if (matches && matches.length === 6) { - addToTree(parseInt(matches[1]), parseInt(matches[2]), matches[5], parseFloat(matches[3]), parseFloat(matches[4])); - } - } + parsePsOutput(stdout, addToTree); if (process.platform === 'linux') { - // Flatten rootItem to get a list of all VSCode processes - let processes = [rootItem]; - const pids: number[] = []; - while (processes.length) { - const process = processes.shift(); - if (process) { - pids.push(process.pid); - if (process.children) { - processes = processes.concat(process.children); - } - } - } - - // The cpu usage value reported on Linux is the average over the process lifetime, - // recalculate the usage over a one second interval - // JSON.stringify is needed to escape spaces, https://github.com/nodejs/node/issues/6803 - let cmd = JSON.stringify(getPathFromAmdModule(require, 'vs/base/node/cpuUsage.sh')); - cmd += ' ' + pids.join(' '); - - exec(cmd, {}, (err, stdout, stderr) => { - if (err || stderr) { - reject(err || new Error(stderr.toString())); - } else { - const cpuUsage = stdout.toString().split('\n'); - for (let i = 0; i < pids.length; i++) { - const processInfo = map.get(pids[i])!; - processInfo.load = parseFloat(cpuUsage[i]); - } - - resolve(rootItem); - } - }); + calculateLinuxCpuUsage(); } else { resolve(rootItem); } - } }); } @@ -229,3 +236,14 @@ export function listProcesses(rootPid: number): Promise { } }); } + +function parsePsOutput(stdout: string, addToTree: (pid: number, ppid: number, cmd: string, load: number, mem: number) => void): void { + const PID_CMD = /^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)\s+(.+)$/; + const lines = stdout.toString().split('\n'); + for (const line of lines) { + const matches = PID_CMD.exec(line.trim()); + if (matches && matches.length === 6) { + addToTree(parseInt(matches[1]), parseInt(matches[2]), matches[5], parseFloat(matches[3]), parseFloat(matches[4])); + } + } +} \ No newline at end of file diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index d2fb152cfe5..85f2ad691ac 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.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 { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; @@ -441,7 +441,7 @@ suite('URI', () => { // let c = 100000; // while (c-- > 0) { for (let value of values) { - let data = value.toJSON(); + let data = value.toJSON() as UriComponents; let clone = URI.revive(data); assert.equal(clone.scheme, value.scheme); diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 65ed00a1eba..c26d967523b 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -88,6 +88,8 @@ export class IssueReporter extends Disposable { os: `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}` }, extensionsDisabled: !!this.environmentService.disableExtensions, + fileOnExtension: configuration.data.extensionId ? true : undefined, + selectedExtension: configuration.data.extensionId ? configuration.data.enabledExtensions.filter(extension => extension.id === configuration.data.extensionId)[0] : undefined }); const issueReporterElement = this.getElementById('issue-reporter'); @@ -698,9 +700,13 @@ export class IssueReporter extends Disposable { private setSourceOptions(): void { const sourceSelect = this.getElementById('issue-source')! as HTMLSelectElement; - const selected = sourceSelect.selectedIndex; + const { issueType, fileOnExtension } = this.issueReporterModel.getData(); + let selected = sourceSelect.selectedIndex; + if (selected === -1 && fileOnExtension !== undefined) { + selected = fileOnExtension ? 2 : 1; + } + sourceSelect.innerHTML = ''; - const { issueType } = this.issueReporterModel.getData(); if (issueType === IssueType.FeatureRequest) { sourceSelect.append(...[ this.makeOption('', localize('selectSource', "Select source"), true), @@ -959,10 +965,15 @@ export class IssueReporter extends Disposable { return 0; }); - const makeOption = (extension: IOption) => ``; + const makeOption = (extension: IOption, selectedExtension?: IssueReporterExtensionData) => { + const selected = selectedExtension && extension.id === selectedExtension.id; + return ``; + }; + const extensionsSelector = this.getElementById('extension-selector'); if (extensionsSelector) { - extensionsSelector.innerHTML = '' + extensionOptions.map(makeOption).join('\n'); + const { selectedExtension } = this.issueReporterModel.getData(); + extensionsSelector.innerHTML = '' + extensionOptions.map(extension => makeOption(extension, selectedExtension)).join('\n'); this.addEventListener('extension-selector', 'change', (e: Event) => { const selectedExtensionId = (e.target).value; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 8db9d0ab91c..adaf6b71bcf 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1754,7 +1754,7 @@ export class EditorModeContext extends Disposable { this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model)); this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model)); this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model)); - this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length > 1 || modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1); + this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length + modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1); this._hasMultipleDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1); this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet); }); diff --git a/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts index eadc88a2545..a6fc98d4760 100644 --- a/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -197,7 +197,7 @@ export class SnippetController2 implements IEditorContribution { insertText: option.value, // insertText: `\${1|${after.concat(before).join(',')}|}$0`, // snippetType: 'textmate', - sortText: repeat('a', i), + sortText: repeat('a', i + 1), range: Range.fromPositions(this._editor.getPosition()!, this._editor.getPosition()!.delta(0, first.value.length)) }; })); diff --git a/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts index 404c78aab22..ef68570326a 100644 --- a/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -343,7 +343,7 @@ export class SuggestModel implements IDisposable { const position = this._editor.getPosition(); const ctx = new LineContext(model, position, this._state === State.Auto, false); this._onNewContext(ctx); - }, 25); + }, 0); } trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set, existingItems?: CompletionItem[]): void { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index b79be56812a..a99de0ecaf3 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -171,8 +171,11 @@ declare namespace monaco { * @param skipEncoding Do not encode the result, default is `false` */ toString(skipEncoding?: boolean): string; - toJSON(): object; - static revive(data: UriComponents | any): Uri; + toJSON(): UriComponents; + static revive(data: UriComponents | Uri): Uri; + static revive(data: UriComponents | Uri | undefined): Uri | undefined; + static revive(data: UriComponents | Uri | null): Uri | null; + static revive(data: UriComponents | Uri | undefined | null): Uri | undefined | null; } export interface UriComponents { diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 2f787370ebe..6dea0f0bc22 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -83,8 +83,21 @@ export interface IConfigurationRegistry { } export const enum ConfigurationScope { + /** + * Application specific configuration, which can be configured only in local user settings. + */ APPLICATION = 1, + /** + * Machine specific configuration, which can be configured only in local and remote user settings. + */ + MACHINE, + /** + * Window specific configuration, which can be configured in the user or workspace settings. + */ WINDOW, + /** + * Resource specific configuration, which can be configured in the user, workspace or folder settings. + */ RESOURCE, } @@ -116,6 +129,7 @@ export interface IDefaultConfigurationExtension { export const allSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} }; export const applicationSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} }; +export const machineSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} }; export const windowSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} }; export const resourceSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} }; @@ -186,6 +200,9 @@ class ConfigurationRegistry implements IConfigurationRegistry { case ConfigurationScope.APPLICATION: delete applicationSettings.properties[key]; break; + case ConfigurationScope.MACHINE: + delete machineSettings.properties[key]; + break; case ConfigurationScope.WINDOW: delete windowSettings.properties[key]; break; @@ -334,6 +351,9 @@ class ConfigurationRegistry implements IConfigurationRegistry { case ConfigurationScope.APPLICATION: applicationSettings.properties[key] = properties[key]; break; + case ConfigurationScope.MACHINE: + machineSettings.properties[key] = properties[key]; + break; case ConfigurationScope.WINDOW: windowSettings.properties[key] = properties[key]; break; @@ -371,6 +391,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { delete allSettings.patternProperties[this.overridePropertyPattern]; delete applicationSettings.patternProperties[this.overridePropertyPattern]; + delete machineSettings.patternProperties[this.overridePropertyPattern]; delete windowSettings.patternProperties[this.overridePropertyPattern]; delete resourceSettings.patternProperties[this.overridePropertyPattern]; @@ -378,6 +399,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { allSettings.patternProperties[this.overridePropertyPattern] = patternProperties; applicationSettings.patternProperties[this.overridePropertyPattern] = patternProperties; + machineSettings.patternProperties[this.overridePropertyPattern] = patternProperties; windowSettings.patternProperties[this.overridePropertyPattern] = patternProperties; resourceSettings.patternProperties[this.overridePropertyPattern] = patternProperties; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 6a70c8a62c4..78923c0be4a 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -188,7 +188,7 @@ function wrapText(text: string, columns: number): string[] { return lines; } -export function buildHelpMessage(productName: string, executableName: string, version: string, isOptionSupported = (_: Option) => true): string { +export function buildHelpMessage(productName: string, executableName: string, version: string, isOptionSupported = (_: Option) => true, isPipeSupported = true): string { const columns = (process.stdout).isTTY && (process.stdout).columns || 80; let categories = new HelpCategories(); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/node/extensionManagementIpc.ts index 9937ddec04c..963e304601e 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementIpc.ts @@ -86,7 +86,7 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer get onDidUninstallExtension(): Event { return this.channel.listen('onDidUninstallExtension'); } zip(extension: ILocalExtension): Promise { - return Promise.resolve(this.channel.call('zip', [extension]).then(result => URI.revive(result))); + return Promise.resolve(this.channel.call('zip', [extension]).then(result => URI.revive(result))); } unzip(zipLocation: URI, type: ExtensionType): Promise { @@ -122,4 +122,4 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer getExtensionsReport(): Promise { return Promise.resolve(this.channel.call('getExtensionsReport')); } -} \ No newline at end of file +} diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 47fab1e6c8e..27a29298f40 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -15,7 +15,7 @@ import { isWindows, isMacintosh } from 'vs/base/common/platform'; import { IWorkspaceIdentifier, IWorkspacesMainService, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IHistoryMainService, IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile } from 'vs/platform/history/common/history'; import { ThrottledDelayer } from 'vs/base/common/async'; -import { isEqual as areResourcesEqual, dirname, originalFSPath } from 'vs/base/common/resources'; +import { isEqual as areResourcesEqual, dirname, originalFSPath, basename } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -29,6 +29,12 @@ export class HistoryMainService implements IHistoryMainService { private static readonly MAX_MACOS_DOCK_RECENT_FOLDERS = 10; private static readonly MAX_MACOS_DOCK_RECENT_FILES = 5; + // Exclude some very common files from the dock/taskbar + private static readonly COMMON_FILES_FILTER = [ + 'COMMIT_EDITMSG', + 'MERGE_MSG' + ]; + private static readonly recentlyOpenedStorageKey = 'openedPathsList'; _serviceBrand: any; @@ -63,8 +69,9 @@ export class HistoryMainService implements IHistoryMainService { } else { if (indexOfFile(files, curr.fileUri) === -1) { files.push(curr); + // Add to recent documents (Windows only, macOS later) - if (isWindows && curr.fileUri.scheme === Schemas.file) { + if (isWindows && curr.fileUri.scheme === Schemas.file && HistoryMainService.COMMON_FILES_FILTER.indexOf(basename(curr.fileUri)) === -1) { app.addRecentDocument(curr.fileUri.fsPath); } } @@ -76,6 +83,7 @@ export class HistoryMainService implements IHistoryMainService { if (workspaces.length > HistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { workspaces.length = HistoryMainService.MAX_TOTAL_RECENT_ENTRIES; } + if (files.length > HistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { files.length = HistoryMainService.MAX_TOTAL_RECENT_ENTRIES; } @@ -143,7 +151,7 @@ export class HistoryMainService implements IHistoryMainService { // Fill in files for (let i = 0, entries = 0; i < mru.files.length && entries < HistoryMainService.MAX_MACOS_DOCK_RECENT_FILES; i++) { const loc = location(mru.files[i]); - if (loc.scheme === Schemas.file) { + if (loc.scheme === Schemas.file && HistoryMainService.COMMON_FILES_FILTER.indexOf(basename(loc)) === -1) { const filePath = originalFSPath(loc); if (await exists(filePath)) { app.addRecentDocument(filePath); @@ -162,7 +170,6 @@ export class HistoryMainService implements IHistoryMainService { } getRecentlyOpened(currentWorkspace?: IWorkspaceIdentifier, currentFolder?: ISingleFolderWorkspaceIdentifier, currentFiles?: IPath[]): IRecentlyOpened { - const workspaces: Array = []; const files: IRecentFile[] = []; @@ -170,6 +177,7 @@ export class HistoryMainService implements IHistoryMainService { if (currentWorkspace && !this.workspacesMainService.isUntitledWorkspace(currentWorkspace)) { workspaces.push({ workspace: currentWorkspace }); } + if (currentFolder) { workspaces.push({ folderUri: currentFolder }); } @@ -183,12 +191,14 @@ export class HistoryMainService implements IHistoryMainService { } } } + this.addEntriesFromStorage(workspaces, files); return { workspaces, files }; } private addEntriesFromStorage(workspaces: Array, files: IRecentFile[]) { + // Get from storage let recents = this.getRecentlyOpenedFromStorage(); for (let recent of recents.workspaces) { @@ -199,6 +209,7 @@ export class HistoryMainService implements IHistoryMainService { workspaces.push(recent); } } + for (let recent of recents.files) { let index = indexOfFile(files, recent.fileUri); if (index >= 0) { @@ -211,11 +222,13 @@ export class HistoryMainService implements IHistoryMainService { private getRecentlyOpenedFromStorage(): IRecentlyOpened { const storedRecents = this.stateService.getItem(HistoryMainService.recentlyOpenedStorageKey); + return restoreRecentlyOpened(storedRecents); } private saveRecentlyOpened(recent: IRecentlyOpened): void { const serialized = toStoreData(recent); + this.stateService.setItem(HistoryMainService.recentlyOpenedStorageKey, serialized); } @@ -268,16 +281,17 @@ export class HistoryMainService implements IHistoryMainService { items: arrays.coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => { const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri; const title = recent.label || getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome); + let description; let args; if (isSingleFolderWorkspaceIdentifier(workspace)) { - const parentFolder = dirname(workspace); - description = nls.localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(parentFolder, this.environmentService)); + description = nls.localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService)); args = `--folder-uri "${workspace.toString()}"`; } else { description = nls.localize('codeWorkspace', "Code Workspace"); args = `--file-uri "${workspace.configPath.toString()}"`; } + return { type: 'task', title, @@ -308,9 +322,11 @@ function location(recent: IRecent): URI { if (isRecentFolder(recent)) { return recent.folderUri; } + if (isRecentFile(recent)) { return recent.fileUri; } + return recent.workspace.configPath; } diff --git a/src/vs/platform/history/electron-main/historyStorage.ts b/src/vs/platform/history/electron-main/historyStorage.ts index b46e6b2cdae..c9175cdb919 100644 --- a/src/vs/platform/history/electron-main/historyStorage.ts +++ b/src/vs/platform/history/electron-main/historyStorage.ts @@ -55,7 +55,7 @@ export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefine result.workspaces.push({ workspace: { id: workspace['id'], configPath: URI.file(workspace['configPath']) } }); } else if (workspace && typeof workspace['path'] === 'string' && typeof workspace['scheme'] === 'string') { // added by 1.26-insiders - result.workspaces.push({ folderUri: URI.revive(workspace) }); + result.workspaces.push({ folderUri: URI.revive(workspace) }); } } } diff --git a/src/vs/platform/issue/common/issue.ts b/src/vs/platform/issue/common/issue.ts index 0058f556840..d9d0e1c4492 100644 --- a/src/vs/platform/issue/common/issue.ts +++ b/src/vs/platform/issue/common/issue.ts @@ -56,6 +56,7 @@ export interface IssueReporterData extends WindowData { styles: IssueReporterStyles; enabledExtensions: IssueReporterExtensionData[]; issueType?: IssueType; + extensionId?: string; } export interface ISettingSearchResult { diff --git a/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts index a82359bdaee..c3830290c6f 100644 --- a/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -30,7 +30,8 @@ export const enum ProgressLocation { Scm = 3, Extensions = 5, Window = 10, - Notification = 15 + Notification = 15, + Dialog = 20 } export interface IProgressOptions { diff --git a/src/vs/platform/telemetry/browser/errorTelemetry.ts b/src/vs/platform/telemetry/browser/errorTelemetry.ts index 0abfe60e009..26380fa6ef0 100644 --- a/src/vs/platform/telemetry/browser/errorTelemetry.ts +++ b/src/vs/platform/telemetry/browser/errorTelemetry.ts @@ -3,69 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { binarySearch } from 'vs/base/common/arrays'; +import { toDisposable } from 'vs/base/common/lifecycle'; import { globals } from 'vs/base/common/platform'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; -import * as Errors from 'vs/base/common/errors'; -import { safeStringify } from 'vs/base/common/objects'; +import BaseErrorTelemetry, { ErrorEvent } from '../common/errorTelemetry'; -/* __GDPR__FRAGMENT__ - "ErrorEvent" : { - "stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" }, - "message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" }, - "filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" }, - "callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, - "msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, - "file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, - "line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, - "uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, - "count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true } - } - */ -interface ErrorEvent { - callstack: string; - msg?: string; - file?: string; - line?: number; - column?: number; - uncaught_error_name?: string; - uncaught_error_msg?: string; - count?: number; -} - -namespace ErrorEvent { - export function compare(a: ErrorEvent, b: ErrorEvent) { - if (a.callstack < b.callstack) { - return -1; - } else if (a.callstack > b.callstack) { - return 1; - } - return 0; - } -} - -export default class ErrorTelemetry { - - public static ERROR_FLUSH_TIMEOUT: number = 5 * 1000; - - private _telemetryService: ITelemetryService; - private _flushDelay: number; - private _flushHandle: any = -1; - private _buffer: ErrorEvent[] = []; - private _disposables: IDisposable[] = []; - - constructor(telemetryService: ITelemetryService, flushDelay = ErrorTelemetry.ERROR_FLUSH_TIMEOUT) { - this._telemetryService = telemetryService; - this._flushDelay = flushDelay; - - // (1) check for unexpected but handled errors - const unbind = Errors.errorHandler.addListener((err) => this._onErrorEvent(err)); - this._disposables.push(toDisposable(unbind)); - - // (2) check for uncaught global errors +export default class ErrorTelemetry extends BaseErrorTelemetry { + protected installErrorListeners(): void { let oldOnError: Function; let that = this; if (typeof globals.onerror === 'function') { @@ -84,37 +27,7 @@ export default class ErrorTelemetry { })); } - dispose() { - clearTimeout(this._flushHandle); - this._flushBuffer(); - this._disposables = dispose(this._disposables); - } - - private _onErrorEvent(err: any): void { - - if (!err) { - return; - } - - // unwrap nested errors from loader - if (err.detail && err.detail.stack) { - err = err.detail; - } - - // work around behavior in workerServer.ts that breaks up Error.stack - let callstack = Array.isArray(err.stack) ? err.stack.join('\n') : err.stack; - let msg = err.message ? err.message : safeStringify(err); - - // errors without a stack are not useful telemetry - if (!callstack) { - return; - } - - this._enqueue({ msg, callstack }); - } - private _onUncaughtError(msg: string, file: string, line: number, column?: number, err?: any): void { - let data: ErrorEvent = { callstack: msg, msg, @@ -138,37 +51,4 @@ export default class ErrorTelemetry { this._enqueue(data); } - - private _enqueue(e: ErrorEvent): void { - - const idx = binarySearch(this._buffer, e, ErrorEvent.compare); - if (idx < 0) { - e.count = 1; - this._buffer.splice(~idx, 0, e); - } else { - if (!this._buffer[idx].count) { - this._buffer[idx].count = 0; - } - this._buffer[idx].count! += 1; - } - - if (this._flushHandle === -1) { - this._flushHandle = setTimeout(() => { - this._flushBuffer(); - this._flushHandle = -1; - }, this._flushDelay); - } - } - - private _flushBuffer(): void { - for (let error of this._buffer) { - /* __GDPR__ - "UnhandledError" : { - "${include}": [ "${ErrorEvent}" ] - } - */ - this._telemetryService.publicLog('UnhandledError', error, true); - } - this._buffer.length = 0; - } } diff --git a/src/vs/platform/telemetry/common/errorTelemetry.ts b/src/vs/platform/telemetry/common/errorTelemetry.ts new file mode 100644 index 00000000000..37be63bfc31 --- /dev/null +++ b/src/vs/platform/telemetry/common/errorTelemetry.ts @@ -0,0 +1,136 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { binarySearch } from 'vs/base/common/arrays'; +import * as Errors from 'vs/base/common/errors'; +import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { safeStringify } from 'vs/base/common/objects'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +/* __GDPR__FRAGMENT__ + "ErrorEvent" : { + "stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" }, + "message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" }, + "filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" }, + "callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, + "msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, + "file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, + "line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, + "uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, + "count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true } + } + */ +export interface ErrorEvent { + callstack: string; + msg?: string; + file?: string; + line?: number; + column?: number; + uncaught_error_name?: string; + uncaught_error_msg?: string; + count?: number; +} + +export namespace ErrorEvent { + export function compare(a: ErrorEvent, b: ErrorEvent) { + if (a.callstack < b.callstack) { + return -1; + } else if (a.callstack > b.callstack) { + return 1; + } + return 0; + } +} + +export default abstract class BaseErrorTelemetry { + + public static ERROR_FLUSH_TIMEOUT: number = 5 * 1000; + + private _telemetryService: ITelemetryService; + private _flushDelay: number; + private _flushHandle: any = -1; + private _buffer: ErrorEvent[] = []; + protected _disposables: IDisposable[] = []; + + constructor(telemetryService: ITelemetryService, flushDelay = BaseErrorTelemetry.ERROR_FLUSH_TIMEOUT) { + this._telemetryService = telemetryService; + this._flushDelay = flushDelay; + + // (1) check for unexpected but handled errors + const unbind = Errors.errorHandler.addListener((err) => this._onErrorEvent(err)); + this._disposables.push(toDisposable(unbind)); + + // (2) install implementation-specific error listeners + this.installErrorListeners(); + } + + dispose() { + clearTimeout(this._flushHandle); + this._flushBuffer(); + this._disposables = dispose(this._disposables); + } + + protected installErrorListeners(): void { + // to override + } + + private _onErrorEvent(err: any): void { + + if (!err) { + return; + } + + // unwrap nested errors from loader + if (err.detail && err.detail.stack) { + err = err.detail; + } + + // work around behavior in workerServer.ts that breaks up Error.stack + let callstack = Array.isArray(err.stack) ? err.stack.join('\n') : err.stack; + let msg = err.message ? err.message : safeStringify(err); + + // errors without a stack are not useful telemetry + if (!callstack) { + return; + } + + this._enqueue({ msg, callstack }); + } + + protected _enqueue(e: ErrorEvent): void { + + const idx = binarySearch(this._buffer, e, ErrorEvent.compare); + if (idx < 0) { + e.count = 1; + this._buffer.splice(~idx, 0, e); + } else { + if (!this._buffer[idx].count) { + this._buffer[idx].count = 0; + } + this._buffer[idx].count! += 1; + } + + if (this._flushHandle === -1) { + this._flushHandle = setTimeout(() => { + this._flushBuffer(); + this._flushHandle = -1; + }, this._flushDelay); + } + } + + private _flushBuffer(): void { + for (let error of this._buffer) { + /* __GDPR__ + "UnhandledError" : { + "${include}": [ "${ErrorEvent}" ] + } + */ + this._telemetryService.publicLog('UnhandledError', error, true); + } + this._buffer.length = 0; + } +} diff --git a/src/vs/platform/telemetry/node/errorTelemetry.ts b/src/vs/platform/telemetry/node/errorTelemetry.ts new file mode 100644 index 00000000000..9cf146e5f6e --- /dev/null +++ b/src/vs/platform/telemetry/node/errorTelemetry.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 { onUnexpectedError } from 'vs/base/common/errors'; +import BaseErrorTelemetry from '../common/errorTelemetry'; + +export default class ErrorTelemetry extends BaseErrorTelemetry { + protected installErrorListeners(): void { + // Print a console message when rejection isn't handled within N seconds. For details: + // see https://nodejs.org/api/process.html#process_event_unhandledrejection + // and https://nodejs.org/api/process.html#process_event_rejectionhandled + const unhandledPromises: Promise[] = []; + process.on('unhandledRejection', (reason: any, promise: Promise) => { + unhandledPromises.push(promise); + setTimeout(() => { + const idx = unhandledPromises.indexOf(promise); + if (idx >= 0) { + promise.catch(e => { + unhandledPromises.splice(idx, 1); + console.warn(`rejected promise not handled within 1 second: ${e}`); + if (e.stack) { + console.warn(`stack trace: ${e.stack}`); + } + onUnexpectedError(reason); + }); + } + }, 1000); + }); + + process.on('rejectionHandled', (promise: Promise) => { + const idx = unhandledPromises.indexOf(promise); + if (idx >= 0) { + unhandledPromises.splice(idx, 1); + } + }); + + // Print a console message when an exception isn't handled. + process.on('uncaughtException', (err: Error) => { + onUnexpectedError(err); + }); + } +} diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 81b5fce5fcd..9fb2ae1d32b 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5973,6 +5973,11 @@ declare module 'vscode' { */ export const appRoot: string; + /** + * The custom uri scheme the editor registers to in the operating system. + */ + export const uriScheme: string; + /** * Represents the preferred user-language, like `de-CH`, `fr`, or `en-US`. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 38b3150b24f..52ab98bc4aa 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -616,11 +616,6 @@ declare module 'vscode' { * An [event](#Event) that fires when the log level has changed. */ export const onDidChangeLogLevel: Event; - - /** - * The custom uri scheme the editor registers to in the operating system, like 'vscode', 'vscode-insiders'. - */ - export const uriScheme: string; } //#endregion diff --git a/src/vs/workbench/api/browser/mainThreadDecorations.ts b/src/vs/workbench/api/browser/mainThreadDecorations.ts index f8ac59feaa3..f34105ddf73 100644 --- a/src/vs/workbench/api/browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/browser/mainThreadDecorations.ts @@ -112,7 +112,7 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { const provider = this._provider.get(handle); if (provider) { const [emitter] = provider; - emitter.fire(resources && resources.map(URI.revive)); + emitter.fire(resources && resources.map(r => URI.revive(r))); } } diff --git a/src/vs/workbench/api/browser/mainThreadSearch.ts b/src/vs/workbench/api/browser/mainThreadSearch.ts index dd1d9ec1df1..5fa7df39b18 100644 --- a/src/vs/workbench/api/browser/mainThreadSearch.ts +++ b/src/vs/workbench/api/browser/mainThreadSearch.ts @@ -162,7 +162,7 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable { }); } else { searchOp.addMatch({ - resource: URI.revive(result) + resource: URI.revive(result) }); } }); diff --git a/src/vs/workbench/api/common/apiCommands.ts b/src/vs/workbench/api/common/apiCommands.ts index 05aebd151ea..c7f4f1972c6 100644 --- a/src/vs/workbench/api/common/apiCommands.ts +++ b/src/vs/workbench/api/common/apiCommands.ts @@ -144,6 +144,13 @@ export class RemoveFromRecentlyOpenedAPICommand { } CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute)); +export class OpenIssueReporter { + public static ID = 'vscode.openIssueReporter'; + public static execute(executor: ICommandsExecutor, extensionId: string): Promise { + return executor.executeCommand('workbench.action.openIssueReporter', [extensionId]); + } +} + interface RecentEntry { uri: URI; type: 'workspace' | 'folder' | 'file'; diff --git a/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts index 1a86479c17c..73969b69470 100644 --- a/src/vs/workbench/api/common/configurationExtensionPoint.ts +++ b/src/vs/workbench/api/common/configurationExtensionPoint.ts @@ -35,16 +35,17 @@ const configurationEntrySchema: IJSONSchema = { properties: { isExecutable: { type: 'boolean', - deprecationMessage: 'This property is deprecated. Instead use `scope` property and set it to `application` value.' + deprecationMessage: 'This property is deprecated. Instead use `scope` property and set it to `machine` value.' }, scope: { type: 'string', - enum: ['application', 'window', 'resource'], + enum: ['application', 'machine', 'window', 'resource'], default: 'window', enumDescriptions: [ - nls.localize('scope.application.description', "Application specific configuration, which can be configured only in User settings."), - nls.localize('scope.window.description', "Window specific configuration, which can be configured in the User or Workspace settings."), - nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the User, Workspace or Folder settings.") + nls.localize('scope.application.description', "Application specific configuration, which can be configured only in local user settings."), + nls.localize('scope.machine.description', "Machine specific configuration, which can be configured only in local and remote user settings."), + nls.localize('scope.window.description', "Window specific configuration, which can be configured in the user or workspace settings."), + nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the user, workspace or folder settings.") ], description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.") }, @@ -210,6 +211,8 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten if (propertyConfiguration.scope) { if (propertyConfiguration.scope.toString() === 'application') { propertyConfiguration.scope = ConfigurationScope.APPLICATION; + } else if (propertyConfiguration.scope.toString() === 'machine') { + propertyConfiguration.scope = ConfigurationScope.MACHINE; } else if (propertyConfiguration.scope.toString() === 'resource') { propertyConfiguration.scope = ConfigurationScope.RESOURCE; } else { diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 737a581ee51..d4f1eb5ba6d 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -15,7 +15,7 @@ import * as search from 'vs/workbench/contrib/search/common/search'; import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures'; -import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands'; +import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter } from './apiCommands'; import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; @@ -258,6 +258,13 @@ export class ExtHostApiCommands { { name: 'layout', description: 'The editor layout to set.', constraint: (value: EditorGroupLayout) => typeof value === 'object' && Array.isArray(value.groups) } ] }); + + this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), { + description: 'Opens the issue reporter with the provided extension id as the selected source', + args: [ + { name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: any) => typeof value === 'string' } + ] + }); } // --- command impl diff --git a/src/vs/workbench/api/common/extHostDialogs.ts b/src/vs/workbench/api/common/extHostDialogs.ts index 1581de27683..06fcd380275 100644 --- a/src/vs/workbench/api/common/extHostDialogs.ts +++ b/src/vs/workbench/api/common/extHostDialogs.ts @@ -17,7 +17,7 @@ export class ExtHostDialogs { showOpenDialog(options: vscode.OpenDialogOptions): Promise { return this._proxy.$showOpenDialog(options).then(filepaths => { - return filepaths ? filepaths.map(URI.revive) : undefined; + return filepaths ? filepaths.map(p => URI.revive(p)) : undefined; }); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index fac19abf67f..2a499df5b16 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -478,8 +478,8 @@ export namespace WorkspaceEdit { ); } else { result.renameFile( - URI.revive((edit).oldUri), - URI.revive((edit).newUri), + URI.revive((edit).oldUri!), + URI.revive((edit).newUri!), (edit).options ); } diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index dc57dbbd1ad..2e6eb740df1 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -420,7 +420,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac } return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token) - .then(data => Array.isArray(data) ? data.map(URI.revive) : []); + .then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : []); } findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index fce140111aa..670b40951ca 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -414,7 +414,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews function reviveWebviewOptions(options: WebviewInputOptions): WebviewInputOptions { return { ...options, - localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(URI.revive) : undefined, + localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined, }; } diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 58d633c7e1e..99e6640c4ba 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -5,7 +5,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as nls from 'vs/nls'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { Action, IAction } from 'vs/base/common/actions'; import { IEditorQuickOpenEntry, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { StatusbarItemDescriptor, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; @@ -142,7 +142,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory { deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): UntitledEditorInput { return instantiationService.invokeFunction(accessor => { const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput); - const resource = !!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource); + const resource = !!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource); const filePath = resource.scheme === Schemas.untitled ? undefined : resource.scheme === Schemas.file ? resource.fsPath : resource.path; const language = deserialized.modeId; const encoding = deserialized.encoding; @@ -925,4 +925,4 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { title: nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"), submenu: MenuId.MenubarSwitchGroupMenu, order: 2 -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 43baae61ba5..3c0544e5f53 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -324,8 +324,8 @@ export class NotificationViewItem extends Disposable implements INotificationVie private static MAX_MESSAGE_LENGTH = 1000; // Example link: "Some message with [link text](http://link.href)." - // RegEx: [, anything not ], ], (, http:|https:, //, no whitespace) - private static LINK_REGEX = /\[([^\]]+)\]\((https?:\/\/[^\)\s]+)\)/gi; + // RegEx: [, anything not ], ], (, http://|https://|command:, no whitespace) + private static LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)\)/gi; private _expanded: boolean; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 44d6ecce76f..75b1edfd663 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -720,11 +720,25 @@ class ReplDelegate implements IListVirtualDelegate { getHeight(element: IReplElement): number { // Give approximate heights. Repl has dynamic height so the tree will measure the actual height on its own. const fontSize = this.configurationService.getValue('debug').console.fontSize; + const rowHeight = Math.ceil(1.4 * fontSize); if (element instanceof Expression && element.hasChildren) { - return Math.ceil(2 * 1.4 * fontSize); + return 2 * rowHeight; } - return Math.ceil(1.4 * fontSize); + // In order to keep scroll position we need to give a good approximation to the tree + if (element instanceof SimpleReplElement) { + // For every 150 characters increase the number of lines needed + let count = Math.ceil(element.value.length / 150); + for (let i = 0; i < element.value.length; i++) { + if (element.value[i] === '\n' || element.value[i] === '\r\n') { + count++; + } + } + + return Math.max(1, count) * rowHeight; + } + + return rowHeight; } getTemplateId(element: IReplElement): string { diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts index 50191d93340..2e4ef24b083 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts @@ -509,7 +509,7 @@ export class DebugService implements IDebugService { // 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905 if (isExtensionHostDebugging(session.configuration) && session.state === State.Running && session.configuration.noDebug) { - this.extensionHostDebugService.close(session.root.uri); + this.extensionHostDebugService.close(session.getId()); } this.telemetryDebugSessionStop(session, adapterExitEvent); @@ -556,8 +556,8 @@ export class DebugService implements IDebugService { return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? session.restart() : undefined); } - if (isExtensionHostDebugging(session.configuration) && session.root) { - return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.root.uri) : undefined); + if (isExtensionHostDebugging(session.configuration)) { + return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.getId()) : undefined); } const shouldFocus = this.viewModel.focusedSession && session.getId() === this.viewModel.focusedSession.getId(); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index c213b10e122..7357cfa53cc 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -606,9 +606,9 @@ export class ExtensionEditor extends BaseEditor { this.renderLocalizations(content, manifest, layout) ]; - const isEmpty = !renders.reduce((v, r) => r || v, false); scrollableContent.scanDomNode(); + const isEmpty = !renders.some(x => x); if (isEmpty) { append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions"); append(this.content, content); diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 4109a95b145..4083f4a6e95 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet'; import * as nls from 'vs/nls'; import { sep } from 'vs/base/common/path'; @@ -157,7 +157,7 @@ class FileEditorInputFactory implements IEditorInputFactory { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { return instantiationService.invokeFunction(accessor => { const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput); - const resource = !!fileInput.resourceJSON ? URI.revive(fileInput.resourceJSON) : URI.parse(fileInput.resource); + const resource = !!fileInput.resourceJSON ? URI.revive(fileInput.resourceJSON) : URI.parse(fileInput.resource); const encoding = fileInput.encoding; return accessor.get(IEditorService).createInput({ resource, encoding, forceFile: true }) as FileEditorInput; diff --git a/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts index e734abdc41b..cbb10f15a37 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts @@ -6,9 +6,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as nls from 'vs/nls'; import product from 'vs/platform/product/node/product'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { SyncActionDescriptor, ICommandAction, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { OpenIssueReporterAction, ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-browser/issueActions'; +import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-browser/issueActions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; import { WorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issueService'; @@ -19,8 +19,27 @@ const helpCategory = nls.localize('help', "Help"); const workbenchActionsRegistry = Registry.as(Extensions.WorkbenchActions); if (!!product.reportIssueUrl) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIssueReporterAction, OpenIssueReporterAction.ID, OpenIssueReporterAction.LABEL), 'Help: Open Issue Reporter', helpCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueUsingReporterAction, ReportPerformanceIssueUsingReporterAction.ID, ReportPerformanceIssueUsingReporterAction.LABEL), 'Help: Report Performance Issue', helpCategory); + + const OpenIssueReporterActionId = 'workbench.action.openIssueReporter'; + const OpenIssueReporterActionLabel = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue"); + + CommandsRegistry.registerCommand(OpenIssueReporterActionId, function (accessor, args?: [string]) { + let extensionId: string | undefined; + if (args && Array.isArray(args)) { + [extensionId] = args; + } + + return accessor.get(IWorkbenchIssueService).openReporter({ extensionId }); + }); + + const command: ICommandAction = { + id: OpenIssueReporterActionId, + title: { value: OpenIssueReporterActionLabel, original: 'Help: Open Issue Reporter' }, + category: helpCategory + }; + + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command }); } const developerCategory = nls.localize('developer', "Developer"); diff --git a/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts b/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts index 884189cbaeb..4eaaf7c3029 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts @@ -8,23 +8,6 @@ import * as nls from 'vs/nls'; import { IssueType } from 'vs/platform/issue/common/issue'; import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; -export class OpenIssueReporterAction extends Action { - static readonly ID = 'workbench.action.openIssueReporter'; - static readonly LABEL = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue"); - - constructor( - id: string, - label: string, - @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService - ) { - super(id, label); - } - - run(): Promise { - return this.issueService.openReporter().then(() => true); - } -} - export class OpenProcessExplorer extends Action { static readonly ID = 'workbench.action.openProcessExplorer'; static readonly LABEL = nls.localize('openProcessExplorer', "Open Process Explorer"); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index d8dc634f821..edc231b62a1 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -256,8 +256,8 @@ export class PreferencesEditor extends BaseEditor { } const promise: Promise = this.input && this.input.isDirty() ? this.input.save() : Promise.resolve(true); promise.then(() => { - if (target === ConfigurationTarget.USER) { - this.preferencesService.switchSettings(ConfigurationTarget.USER, this.preferencesService.userSettingsResource, true); + if (target === ConfigurationTarget.USER_LOCAL) { + this.preferencesService.switchSettings(ConfigurationTarget.USER_LOCAL, this.preferencesService.userSettingsResource, true); } else if (target === ConfigurationTarget.WORKSPACE) { this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE, this.preferencesService.workspaceSettingsResource!, true); } else if (target instanceof URI) { @@ -507,7 +507,7 @@ class PreferencesRenderersController extends Disposable { private searchAllSettingsTargets(query: string, searchProvider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number, token?: CancellationToken): Promise { const searchPs = [ this.searchSettingsTarget(query, searchProvider, ConfigurationTarget.WORKSPACE, groupId, groupLabel, groupOrder, token), - this.searchSettingsTarget(query, searchProvider, ConfigurationTarget.USER, groupId, groupLabel, groupOrder, token) + this.searchSettingsTarget(query, searchProvider, ConfigurationTarget.USER_LOCAL, groupId, groupLabel, groupOrder, token) ]; for (const folder of this.workspaceContextService.getWorkspace().folders) { @@ -541,9 +541,10 @@ class PreferencesRenderersController extends Disposable { } private async getPreferencesEditorModel(target: SettingsTarget | undefined): Promise { - const resource = target === ConfigurationTarget.USER ? this.preferencesService.userSettingsResource : - target === ConfigurationTarget.WORKSPACE ? this.preferencesService.workspaceSettingsResource : - target; + const resource = target === ConfigurationTarget.USER_LOCAL ? this.preferencesService.userSettingsResource : + target === ConfigurationTarget.USER_REMOTE ? this.preferencesService.userSettingsResource : + target === ConfigurationTarget.WORKSPACE ? this.preferencesService.workspaceSettingsResource : + target; if (!resource) { return undefined; @@ -821,7 +822,7 @@ class SideBySidePreferencesWidget extends Widget { this.editablePreferencesEditorContainer = DOM.$('.editable-preferences-editor-container'); const editablePreferencesHeaderContainer = DOM.append(this.editablePreferencesEditorContainer, DOM.$('.preferences-header-container')); - this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, editablePreferencesHeaderContainer)); + this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, editablePreferencesHeaderContainer, undefined)); this._register(this.settingsTargetsWidget.onDidTargetChange(target => this._onDidSettingsTargetChange.fire(target))); this._register(attachStylerCallback(this.themeService, { scrollbarShadow }, colors => { @@ -865,7 +866,7 @@ class SideBySidePreferencesWidget extends Widget { private getDefaultPreferencesHeaderText(target: ConfigurationTarget): string { switch (target) { - case ConfigurationTarget.USER: + case ConfigurationTarget.USER_LOCAL: return nls.localize('defaultUserSettings', "Default User Settings"); case ConfigurationTarget.WORKSPACE: return nls.localize('defaultWorkspaceSettings', "Default Workspace Settings"); @@ -942,7 +943,7 @@ class SideBySidePreferencesWidget extends Widget { private getSettingsTarget(resource: URI): SettingsTarget { if (this.preferencesService.userSettingsResource.toString() === resource.toString()) { - return ConfigurationTarget.USER; + return ConfigurationTarget.USER_LOCAL; } const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource; @@ -955,7 +956,7 @@ class SideBySidePreferencesWidget extends Widget { return folder.uri; } - return ConfigurationTarget.USER; + return ConfigurationTarget.USER_LOCAL; } private disposeEditors(): void { @@ -1202,7 +1203,7 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl .then(settingsModel => { if (settingsModel instanceof SettingsEditorModel && this.editor.getModel()) { switch (settingsModel.configurationTarget) { - case ConfigurationTarget.USER: + case ConfigurationTarget.USER_LOCAL: return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel); case ConfigurationTarget.WORKSPACE: return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index b63bba31943..8faa20df1ce 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -24,11 +24,14 @@ import { ConfigurationTarget } from 'vs/platform/configuration/common/configurat import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { activeContrastBorder, badgeBackground, badgeForeground, contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND } from 'vs/workbench/common/theme'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; export class SettingsHeaderWidget extends Widget implements IViewZone { @@ -464,14 +467,20 @@ export class FolderSettingsActionItem extends BaseActionItem { } } -export type SettingsTarget = ConfigurationTarget.USER | ConfigurationTarget.WORKSPACE | URI; +export type SettingsTarget = ConfigurationTarget.USER_LOCAL | ConfigurationTarget.USER_REMOTE | ConfigurationTarget.WORKSPACE | URI; + +export interface ISettingsTargetsWidgetOptions { + enableRemoteSettings?: boolean; +} export class SettingsTargetsWidget extends Widget { private settingsSwitcherBar: ActionBar; - private userSettings: Action; + private userLocalSettings: Action; + private userRemoteSettings: Action; private workspaceSettings: Action; private folderSettings: FolderSettingsActionItem; + private options: ISettingsTargetsWidgetOptions; private _settingsTarget: SettingsTarget; @@ -480,10 +489,14 @@ export class SettingsTargetsWidget extends Widget { constructor( parent: HTMLElement, + options: ISettingsTargetsWidgetOptions | undefined, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @ILabelService private readonly labelService: ILabelService ) { super(); + this.options = options || {}; this.create(parent); this._register(this.contextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged())); this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update())); @@ -498,18 +511,25 @@ export class SettingsTargetsWidget extends Widget { actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined })); - this.userSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER)); - this.userSettings.tooltip = this.userSettings.label; + this.userLocalSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL)); + this.userLocalSettings.tooltip = this.userLocalSettings.label; + + const remoteAuthority = this.environmentService.configuration.remoteAuthority; + const hostLabel = remoteAuthority && this.labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority); + const remoteSettingsLabel = localize('userSettingsRemote', "Remote Settings") + + (hostLabel ? ` (${hostLabel})` : ''); + this.userRemoteSettings = new Action('userSettingsRemote', remoteSettingsLabel, '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE)); + this.userRemoteSettings.tooltip = this.userRemoteSettings.label; this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace Settings"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE)); this.workspaceSettings.tooltip = this.workspaceSettings.label; - const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder Settings"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder ? folder.uri : ConfigurationTarget.USER)); + const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder Settings"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri)); this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction); this.update(); - this.settingsSwitcherBar.push([this.userSettings, this.workspaceSettings, folderSettingsAction]); + this.settingsSwitcherBar.push([this.userLocalSettings, this.userRemoteSettings, this.workspaceSettings, folderSettingsAction]); } get settingsTarget(): SettingsTarget { @@ -518,7 +538,8 @@ export class SettingsTargetsWidget extends Widget { set settingsTarget(settingsTarget: SettingsTarget) { this._settingsTarget = settingsTarget; - this.userSettings.checked = ConfigurationTarget.USER === this.settingsTarget; + this.userLocalSettings.checked = ConfigurationTarget.USER_LOCAL === this.settingsTarget; + this.userRemoteSettings.checked = ConfigurationTarget.USER_REMOTE === this.settingsTarget; this.workspaceSettings.checked = ConfigurationTarget.WORKSPACE === this.settingsTarget; if (this.settingsTarget instanceof URI) { this.folderSettings.getAction().checked = true; @@ -536,13 +557,13 @@ export class SettingsTargetsWidget extends Widget { } this.workspaceSettings.label = label; - } else if (settingsTarget === ConfigurationTarget.USER) { + } else if (settingsTarget === ConfigurationTarget.USER_LOCAL) { let label = localize('userSettings', "User Settings"); if (count) { label += ` (${count})`; } - this.userSettings.label = label; + this.userLocalSettings.label = label; } else if (settingsTarget instanceof URI) { this.folderSettings.setCount(settingsTarget, count); } @@ -552,21 +573,27 @@ export class SettingsTargetsWidget extends Widget { this.folderSettings.folder = null; this.update(); if (this.settingsTarget === ConfigurationTarget.WORKSPACE && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - this.updateTarget(ConfigurationTarget.USER); + this.updateTarget(ConfigurationTarget.USER_LOCAL); } } updateTarget(settingsTarget: SettingsTarget): Promise { - const isSameTarget = this.settingsTarget === settingsTarget || settingsTarget instanceof URI && this.settingsTarget instanceof URI && this.settingsTarget.toString() === settingsTarget.toString(); + const isSameTarget = this.settingsTarget === settingsTarget || + settingsTarget instanceof URI && + this.settingsTarget instanceof URI && + this.settingsTarget.toString() === settingsTarget.toString(); + if (!isSameTarget) { this.settingsTarget = settingsTarget; this._onDidTargetChange.fire(this.settingsTarget); } + return Promise.resolve(undefined); } private update(): void { DOM.toggleClass(this.settingsSwitcherBar.domNode, 'empty-workbench', this.contextService.getWorkbenchState() === WorkbenchState.EMPTY); + this.userRemoteSettings.enabled = !!(this.options.enableRemoteSettings && this.environmentService.configuration.remoteAuthority); this.workspaceSettings.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; this.folderSettings.getAction().enabled = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.contextService.getWorkspace().folders.length > 0; } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 69d65e71352..59a36d4f50b 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1174,7 +1174,7 @@ export class SettingsTreeFilter implements ITreeFilter { } // Non-user scope selected - if (element instanceof SettingsTreeSettingElement && this.viewState.settingsTarget !== ConfigurationTarget.USER) { + if (element instanceof SettingsTreeSettingElement && this.viewState.settingsTarget !== ConfigurationTarget.USER_LOCAL) { if (!element.matchesScope(this.viewState.settingsTarget)) { return false; } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index c921692d541..d277272f4be 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -337,9 +337,10 @@ interface IInspectResult { function inspectSetting(key: string, target: SettingsTarget, configurationService: IConfigurationService): IInspectResult { const inspectOverrides = URI.isUri(target) ? { resource: target } : undefined; const inspected = configurationService.inspect(key, inspectOverrides); - const targetSelector = target === ConfigurationTarget.USER ? 'user' : - target === ConfigurationTarget.WORKSPACE ? 'workspace' : - 'workspaceFolder'; + const targetSelector = target === ConfigurationTarget.USER_LOCAL ? 'userLocal' : + target === ConfigurationTarget.USER_REMOTE ? 'userRemote' : + target === ConfigurationTarget.WORKSPACE ? 'workspace' : + 'workspaceFolder'; const isConfigured = typeof inspected[targetSelector] !== 'undefined'; return { isConfigured, inspected, targetSelector }; diff --git a/src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts index 6b0de094ef0..1985393f0c4 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts @@ -149,7 +149,7 @@ export class SettingsEditor2 extends BaseEditor { this.delayedFilterLogging = new Delayer(1000); this.localSearchDelayer = new Delayer(300); this.remoteSearchThrottle = new ThrottledDelayer(200); - this.viewState = { settingsTarget: ConfigurationTarget.USER }; + this.viewState = { settingsTarget: ConfigurationTarget.USER_LOCAL }; this.settingFastUpdateDelayer = new Delayer(SettingsEditor2.SETTING_UPDATE_FAST_DEBOUNCE); this.settingSlowUpdateDelayer = new Delayer(SettingsEditor2.SETTING_UPDATE_SLOW_DEBOUNCE); @@ -212,10 +212,10 @@ export class SettingsEditor2 extends BaseEditor { if (!options) { if (!this.viewState.settingsTarget) { // Persist? - options = SettingsEditorOptions.create({ target: ConfigurationTarget.USER }); + options = SettingsEditorOptions.create({ target: ConfigurationTarget.USER_LOCAL }); } } else if (!options.target) { - options.target = ConfigurationTarget.USER; + options.target = ConfigurationTarget.USER_LOCAL; } this._setOptions(options); @@ -406,8 +406,8 @@ export class SettingsEditor2 extends BaseEditor { const headerControlsContainer = DOM.append(this.headerContainer, $('.settings-header-controls')); const targetWidgetContainer = DOM.append(headerControlsContainer, $('.settings-target-container')); - this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer)); - this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER; + this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer, { enableRemoteSettings: true })); + this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER_LOCAL; this.settingsTargetsWidget.onDidTargetChange(target => this.onDidSettingsTargetChange(target)); } @@ -458,8 +458,10 @@ export class SettingsEditor2 extends BaseEditor { const currentSettingsTarget = this.settingsTargetsWidget.settingsTarget; const options: ISettingsEditorOptions = { query }; - if (currentSettingsTarget === ConfigurationTarget.USER) { + if (currentSettingsTarget === ConfigurationTarget.USER_LOCAL) { return this.preferencesService.openGlobalSettings(true, options); + } else if (currentSettingsTarget === ConfigurationTarget.USER_REMOTE) { + return this.preferencesService.openRemoteSettings(); } else if (currentSettingsTarget === ConfigurationTarget.WORKSPACE) { return this.preferencesService.openWorkspaceSettings(true, options); } else { @@ -615,8 +617,10 @@ export class SettingsEditor2 extends BaseEditor { this._register(this.settingRenderers.onDidClickOverrideElement((element: ISettingOverrideClickEvent) => { if (ConfigurationTargetToString(ConfigurationTarget.WORKSPACE) === element.scope.toUpperCase()) { this.settingsTargetsWidget.updateTarget(ConfigurationTarget.WORKSPACE); - } else if (ConfigurationTargetToString(ConfigurationTarget.USER) === element.scope.toUpperCase()) { - this.settingsTargetsWidget.updateTarget(ConfigurationTarget.USER); + } else if (ConfigurationTargetToString(ConfigurationTarget.USER_LOCAL) === element.scope.toUpperCase()) { + this.settingsTargetsWidget.updateTarget(ConfigurationTarget.USER_LOCAL); + } else if (ConfigurationTargetToString(ConfigurationTarget.USER_REMOTE) === element.scope.toUpperCase()) { + this.settingsTargetsWidget.updateTarget(ConfigurationTarget.USER_REMOTE); } this.searchWidget.setValue(element.targetKey); @@ -792,9 +796,10 @@ export class SettingsEditor2 extends BaseEditor { } } - const reportedTarget = props.settingsTarget === ConfigurationTarget.USER ? 'user' : - props.settingsTarget === ConfigurationTarget.WORKSPACE ? 'workspace' : - 'folder'; + const reportedTarget = props.settingsTarget === ConfigurationTarget.USER_LOCAL ? 'user' : + props.settingsTarget === ConfigurationTarget.USER_REMOTE ? 'user_remote' : + props.settingsTarget === ConfigurationTarget.WORKSPACE ? 'workspace' : + 'folder'; const data = { key: props.key, diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index 34c0dd2a005..04b592967df 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -85,7 +85,8 @@ class PartsSplash { colorInfo, layoutInfo, baseTheme - }) + }), + { encoding: 'utf8', overwriteEncoding: true } ); if (baseTheme !== this._lastBaseTheme || colorInfo.editorBackground !== this._lastBackground) { diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 8c4b7a71963..755efd95864 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -526,7 +526,7 @@ export class ElectronWindow extends Disposable { const resource = URI.revive(p.fileUri); let input: IResourceInput | IUntitledResourceInput; if (isNew) { - input = { filePath: resource.fsPath, options: { pinned: true } }; + input = { filePath: resource!.fsPath, options: { pinned: true } }; } else { input = { resource, options: { pinned: true } }; } diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index efbd303489d..78957e2c301 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -18,10 +18,10 @@ import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, IConfigurationFileService, machineSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings } from 'vs/platform/configuration/common/configurationRegistry'; +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'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService'; +import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService'; 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'; @@ -269,6 +269,8 @@ export class WorkspaceService extends Disposable implements IConfigurationServic inspect(key: string, overrides?: IConfigurationOverrides): { default: T, user: T, + userLocal?: T, + userRemote?: T, workspace?: T, workspaceFolder?: T, memory?: T, @@ -419,8 +421,15 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private reloadUserConfiguration(key?: string): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> { - return Promise.all([this.localUserConfiguration ? this.localUserConfiguration.reload() : Promise.resolve(new ConfigurationModel()), this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel())]) - .then(([local, remote]) => ({ local, remote })); + return Promise.all([this.reloadLocalUserConfiguration(), this.reloadRemoeUserConfiguration()]).then(([local, remote]) => ({ local, remote })); + } + + private reloadLocalUserConfiguration(key?: string): Promise { + return this.localUserConfiguration ? this.localUserConfiguration.reload() : Promise.resolve(new ConfigurationModel()); + } + + private reloadRemoeUserConfiguration(key?: string): Promise { + return this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel()); } private reloadWorkspaceConfiguration(key?: string): Promise { @@ -503,16 +512,18 @@ export class WorkspaceService extends Disposable implements IConfigurationServic }; const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; - const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in User Settings")); - const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + 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 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' }; jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema); jsonRegistry.registerSchema(userSettingsSchemaId, allSettingsSchema); - jsonRegistry.registerSchema(machineSettingsSchemaId, workspaceSettingsSchema); + 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, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema); jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema); } else { @@ -613,20 +624,25 @@ export class WorkspaceService extends Disposable implements IConfigurationServic return Promise.resolve(undefined); } - return this.configurationEditingService.writeConfiguration(target, { key, value }, { scopes: overrides, donotNotifyError }) + const editableConfigurationTarget = this.toEditableConfigurationTarget(target, key); + if (!editableConfigurationTarget) { + return Promise.reject(new Error('Invalid configuration target')); + } + + if (editableConfigurationTarget === EditableConfigurationTarget.USER_REMOTE && !this.remoteUserConfiguration) { + return Promise.reject(new Error('Invalid configuration target')); + } + + return this.configurationEditingService.writeConfiguration(editableConfigurationTarget, { key, value }, { scopes: overrides, donotNotifyError }) .then(() => { - switch (target) { - case ConfigurationTarget.USER: - return this.reloadUserConfiguration() - .then(({ local, remote }) => { - this.onLocalUserConfigurationChanged(local); - if (this.remoteUserConfiguration) { - this.onRemoteUserConfigurationChanged(remote); - } - }); - case ConfigurationTarget.WORKSPACE: + switch (editableConfigurationTarget) { + case EditableConfigurationTarget.USER_LOCAL: + return this.reloadLocalUserConfiguration().then(local => this.onLocalUserConfigurationChanged(local)); + case EditableConfigurationTarget.USER_REMOTE: + return this.reloadRemoeUserConfiguration().then(remote => this.onRemoteUserConfigurationChanged(remote)); + case EditableConfigurationTarget.WORKSPACE: return this.reloadWorkspaceConfiguration(); - case ConfigurationTarget.WORKSPACE_FOLDER: + case EditableConfigurationTarget.WORKSPACE_FOLDER: const workspaceFolder = overrides && overrides.resource ? this.workspace.getFolder(overrides.resource) : null; if (workspaceFolder) { return this.reloadWorkspaceFolderConfiguration(workspaceFolder, key); @@ -681,4 +697,26 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } return {}; } + + private toEditableConfigurationTarget(target: ConfigurationTarget, key: string): EditableConfigurationTarget | null { + if (target === ConfigurationTarget.USER) { + if (this.inspect(key).userRemote !== undefined) { + return EditableConfigurationTarget.USER_REMOTE; + } + return EditableConfigurationTarget.USER_LOCAL; + } + if (target === ConfigurationTarget.USER_LOCAL) { + return EditableConfigurationTarget.USER_LOCAL; + } + if (target === ConfigurationTarget.USER_REMOTE) { + return EditableConfigurationTarget.USER_REMOTE; + } + if (target === ConfigurationTarget.WORKSPACE) { + return EditableConfigurationTarget.WORKSPACE; + } + if (target === ConfigurationTarget.WORKSPACE_FOLDER) { + return EditableConfigurationTarget.WORKSPACE_FOLDER; + } + return null; + } } \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index 7c3a06db189..c8ec23ec441 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -20,7 +20,7 @@ export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; export const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; export const launchSchemaId = 'vscode://schemas/launch'; -export const MACHINE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; +export const MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; export const WORKSPACE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; export const FOLDER_SCOPES = [ConfigurationScope.RESOURCE]; diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index c299913d7d4..7f4147d64a3 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -18,7 +18,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration'; import { FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; @@ -42,6 +42,11 @@ export const enum ConfigurationEditingErrorCode { */ ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, + /** + * Error when trying to write a machne setting into workspace settings. + */ + ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE, + /** * Error when trying to write an invalid folder configuration key to folder settings. */ @@ -104,8 +109,15 @@ export interface IConfigurationEditingOptions { scopes?: IConfigurationOverrides; } +export const enum EditableConfigurationTarget { + USER_LOCAL = 1, + USER_REMOTE, + WORKSPACE, + WORKSPACE_FOLDER +} + interface IConfigurationEditOperation extends IConfigurationValue { - target: ConfigurationTarget; + target: EditableConfigurationTarget; jsonPath: json.JSONPath; resource?: URI; workspaceStandAloneConfigurationKey?: string; @@ -143,7 +155,7 @@ export class ConfigurationEditingService { }); } - writeConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): Promise { + writeConfiguration(target: EditableConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): Promise { const operation = this.getConfigurationEditOperation(target, value, options.scopes || {}); return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(operation, options) // queue up writes to prevent race conditions .then(() => null, @@ -251,13 +263,16 @@ export class ConfigurationEditingService { private openSettings(operation: IConfigurationEditOperation): void { switch (operation.target) { - case ConfigurationTarget.USER: + case EditableConfigurationTarget.USER_LOCAL: this.preferencesService.openGlobalSettings(true); break; - case ConfigurationTarget.WORKSPACE: + case EditableConfigurationTarget.USER_REMOTE: + this.preferencesService.openRemoteSettings(); + break; + case EditableConfigurationTarget.WORKSPACE: this.preferencesService.openWorkspaceSettings(true); break; - case ConfigurationTarget.WORKSPACE_FOLDER: + case EditableConfigurationTarget.WORKSPACE_FOLDER: if (operation.resource) { const workspaceFolder = this.contextService.getWorkspaceFolder(operation.resource); if (workspaceFolder) { @@ -272,18 +287,19 @@ export class ConfigurationEditingService { this.editorService.openEditor({ resource }); } - private reject(code: ConfigurationEditingErrorCode, target: ConfigurationTarget, operation: IConfigurationEditOperation): Promise { + private reject(code: ConfigurationEditingErrorCode, target: EditableConfigurationTarget, operation: IConfigurationEditOperation): Promise { const message = this.toErrorMessage(code, target, operation); return Promise.reject(new ConfigurationEditingError(message, code)); } - private toErrorMessage(error: ConfigurationEditingErrorCode, target: ConfigurationTarget, operation: IConfigurationEditOperation): string { + private toErrorMessage(error: ConfigurationEditingErrorCode, target: EditableConfigurationTarget, operation: IConfigurationEditOperation): string { switch (error) { // API constraints case ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY: return nls.localize('errorUnknownKey', "Unable to write to {0} because {1} is not a registered configuration.", this.stringifyTarget(target), operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION: return nls.localize('errorInvalidWorkspaceConfigurationApplication', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.key); + case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE: return nls.localize('errorInvalidWorkspaceConfigurationMachine', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION: return nls.localize('errorInvalidFolderConfiguration', "Unable to write to Folder Settings because {0} does not support the folder resource scope.", operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET: return nls.localize('errorInvalidUserTarget', "Unable to write to User Settings because {0} does not support for global scope.", operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET: return nls.localize('errorInvalidWorkspaceTarget', "Unable to write to Workspace Settings because {0} does not support for workspace scope in a multi folder workspace.", operation.key); @@ -299,11 +315,13 @@ export class ConfigurationEditingService { return nls.localize('errorInvalidLaunchConfiguration', "Unable to write into the launch configuration file. Please open it to correct errors/warnings in it and try again."); } switch (target) { - case ConfigurationTarget.USER: + case EditableConfigurationTarget.USER_LOCAL: return nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open the user settings to correct errors/warnings in it and try again."); - case ConfigurationTarget.WORKSPACE: + case EditableConfigurationTarget.USER_REMOTE: + return nls.localize('errorInvalidRemoteConfiguration', "Unable to write into remote user settings. Please open the remote user settings to correct errors/warnings in it and try again."); + case EditableConfigurationTarget.WORKSPACE: return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open the workspace settings to correct errors/warnings in the file and try again."); - case ConfigurationTarget.WORKSPACE_FOLDER: + case EditableConfigurationTarget.WORKSPACE_FOLDER: let workspaceFolderName: string = '<>'; if (operation.resource) { const folder = this.contextService.getWorkspaceFolder(operation.resource); @@ -323,11 +341,13 @@ export class ConfigurationEditingService { return nls.localize('errorLaunchConfigurationFileDirty', "Unable to write into launch configuration file because the file is dirty. Please save it first and then try again."); } switch (target) { - case ConfigurationTarget.USER: + case EditableConfigurationTarget.USER_LOCAL: return nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the user settings file first and then try again."); - case ConfigurationTarget.WORKSPACE: + case EditableConfigurationTarget.USER_REMOTE: + return nls.localize('errorRemoteConfigurationFileDirty', "Unable to write into remote user settings because the file is dirty. Please save the remote user settings file first and then try again."); + case EditableConfigurationTarget.WORKSPACE: return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the workspace settings file first and then try again."); - case ConfigurationTarget.WORKSPACE_FOLDER: + case EditableConfigurationTarget.WORKSPACE_FOLDER: let workspaceFolderName: string = '<>'; if (operation.resource) { const folder = this.contextService.getWorkspaceFolder(operation.resource); @@ -342,13 +362,15 @@ export class ConfigurationEditingService { } } - private stringifyTarget(target: ConfigurationTarget): string { + private stringifyTarget(target: EditableConfigurationTarget): string { switch (target) { - case ConfigurationTarget.USER: + case EditableConfigurationTarget.USER_LOCAL: return nls.localize('userTarget', "User Settings"); - case ConfigurationTarget.WORKSPACE: + case EditableConfigurationTarget.USER_REMOTE: + return nls.localize('remoteUserTarget', "Remote User Settings"); + case EditableConfigurationTarget.WORKSPACE: return nls.localize('workspaceTarget', "Workspace Settings"); - case ConfigurationTarget.WORKSPACE_FOLDER: + case EditableConfigurationTarget.WORKSPACE_FOLDER: return nls.localize('folderTarget', "Folder Settings"); } return ''; @@ -375,7 +397,7 @@ export class ConfigurationEditingService { private async resolveModelReference(resource: URI): Promise> { const exists = await this.fileService.exists(resource); if (!exists) { - await this.textFileService.write(resource, '{}'); + await this.textFileService.write(resource, '{}', { encoding: 'utf8' }); } return this.textModelResolverService.createModelReference(resource); } @@ -391,7 +413,7 @@ export class ConfigurationEditingService { return parseErrors.length > 0; } - private resolveAndValidate(target: ConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): Promise> { + private resolveAndValidate(target: EditableConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): Promise> { // Any key must be a known setting from the registry (unless this is a standalone config) if (!operation.workspaceStandAloneConfigurationKey) { @@ -403,31 +425,34 @@ export class ConfigurationEditingService { if (operation.workspaceStandAloneConfigurationKey) { // Global tasks and launches are not supported - if (target === ConfigurationTarget.USER) { + if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation); } // Workspace tasks are not supported - if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === ConfigurationTarget.WORKSPACE) { + if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === EditableConfigurationTarget.WORKSPACE) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, target, operation); } } // Target cannot be workspace or folder if no workspace opened - if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + if ((target === EditableConfigurationTarget.WORKSPACE || target === EditableConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { return this.reject(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, target, operation); } - if (target === ConfigurationTarget.WORKSPACE) { + if (target === EditableConfigurationTarget.WORKSPACE) { if (!operation.workspaceStandAloneConfigurationKey) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[operation.key].scope === ConfigurationScope.APPLICATION) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, target, operation); } + if (configurationProperties[operation.key].scope === ConfigurationScope.MACHINE) { + return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE, target, operation); + } } } - if (target === ConfigurationTarget.WORKSPACE_FOLDER) { + if (target === EditableConfigurationTarget.WORKSPACE_FOLDER) { if (!operation.resource) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation); } @@ -460,7 +485,7 @@ export class ConfigurationEditingService { }); } - private getConfigurationEditOperation(target: ConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation { + private getConfigurationEditOperation(target: EditableConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation { // Check for standalone workspace configurations if (config.key) { @@ -485,7 +510,7 @@ export class ConfigurationEditingService { let key = config.key; let jsonPath = overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier), key] : [key]; - if (target === ConfigurationTarget.USER) { + if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) { return { key, jsonPath, value: config.value, resource: withNullAsUndefined(this.getConfigurationFileResource(target, config, '', null)), target }; } @@ -501,26 +526,19 @@ export class ConfigurationEditingService { return !!(workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath); } - private getConfigurationFileResource(target: ConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null { - if (target === ConfigurationTarget.USER_LOCAL) { + private getConfigurationFileResource(target: EditableConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null { + if (target === EditableConfigurationTarget.USER_LOCAL) { return URI.file(this.environmentService.appSettingsPath); } - if (target === ConfigurationTarget.USER_REMOTE) { + if (target === EditableConfigurationTarget.USER_REMOTE) { return this.remoteSettingsResource; } - if (target === ConfigurationTarget.USER) { - if (this.configurationService.inspect(config.key).userRemote !== undefined) { - return this.remoteSettingsResource; - } - return URI.file(this.environmentService.appSettingsPath); - } - const workbenchState = this.contextService.getWorkbenchState(); if (workbenchState !== WorkbenchState.EMPTY) { const workspace = this.contextService.getWorkspace(); - if (target === ConfigurationTarget.WORKSPACE) { + if (target === EditableConfigurationTarget.WORKSPACE) { if (workbenchState === WorkbenchState.WORKSPACE) { return withUndefinedAsNull(workspace.configuration); } @@ -529,7 +547,7 @@ export class ConfigurationEditingService { } } - if (target === ConfigurationTarget.WORKSPACE_FOLDER) { + if (target === EditableConfigurationTarget.WORKSPACE_FOLDER) { if (resource) { const folder = this.contextService.getWorkspaceFolder(resource); if (folder) { diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index e9ac592d79c..7a30ad06477 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -97,6 +97,8 @@ export class Configuration extends BaseConfiguration { inspect(key: string, overrides: IConfigurationOverrides = {}): { default: C, user: C, + userLocal?: C, + userRemote?: C, workspace?: C, workspaceFolder?: C memory?: C diff --git a/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts index 7916884a275..baeccb314dd 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditingService.ts @@ -86,7 +86,7 @@ export class JSONEditingService implements IJSONEditingService { private async resolveModelReference(resource: URI): Promise> { const exists = await this.fileService.exists(resource); if (!exists) { - await this.textFileService.write(resource, '{}'); + await this.textFileService.write(resource, '{}', { encoding: 'utf8' }); } return this.textModelResolverService.createModelReference(resource); } diff --git a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts index 43d13d5ada3..950b215df35 100644 --- a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts +++ b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts @@ -35,6 +35,11 @@ suite('FolderSettingsModelParser', () => { 'type': 'string', 'default': 'isSet', scope: ConfigurationScope.APPLICATION + }, + 'FolderSettingsModelParser.machine': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE } } }); @@ -43,7 +48,7 @@ suite('FolderSettingsModelParser', () => { test('parse all folder settings', () => { const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW]); - testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'executable' })); + testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' })); assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'window': 'window', 'resource': 'resource' } }); }); @@ -51,7 +56,7 @@ suite('FolderSettingsModelParser', () => { test('parse resource folder settings', () => { const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE]); - testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'executable' })); + testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' })); assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'resource': 'resource' } }); }); @@ -59,12 +64,12 @@ suite('FolderSettingsModelParser', () => { test('parse overridable resource settings', () => { const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE]); - testObject.parseContent(JSON.stringify({ '[json]': { 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'executable' } })); + testObject.parseContent(JSON.stringify({ '[json]': { 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' } })); assert.deepEqual(testObject.configurationModel.overrides, [{ 'contents': { 'FolderSettingsModelParser': { 'resource': 'resource' } }, 'identifiers': ['json'] }]); }); - test('reprocess folder settings excludes application setting', () => { + test('reprocess folder settings excludes application and machine setting', () => { const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW]); testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.anotherApplicationSetting': 'executable' })); @@ -80,6 +85,11 @@ suite('FolderSettingsModelParser', () => { 'type': 'string', 'default': 'isSet', scope: ConfigurationScope.APPLICATION + }, + 'FolderSettingsModelParser.anotherMachineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE } } }); 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 6e6f0cf18ca..d5bd26501f7 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 @@ -19,9 +19,9 @@ import * as uuid from 'vs/base/common/uuid'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; import { LegacyFileService } from 'vs/workbench/services/files/node/fileService'; -import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/common/configurationEditingService'; +import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; -import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -152,41 +152,41 @@ suite('ConfigurationEditingService', () => { } test('errors cases - invalid key', () => { - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'unknown.key', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'unknown.key', value: 'value' }) .then(() => assert.fail('Should fail with ERROR_UNKNOWN_KEY'), (error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY)); }); test('errors cases - invalid target', () => { - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'tasks.something', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks.something', value: 'value' }) .then(() => assert.fail('Should fail with ERROR_INVALID_TARGET'), (error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET)); }); test('errors cases - no workspace', () => { return setUpServices(true) - .then(() => testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'configurationEditing.service.testSetting', value: 'value' })) + .then(() => testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'configurationEditing.service.testSetting', value: 'value' })) .then(() => assert.fail('Should fail with ERROR_NO_WORKSPACE_OPENED'), (error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED)); }); test('errors cases - invalid configuration', () => { fs.writeFileSync(globalSettingsFile, ',,,,,,,,,,,,,,'); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }) .then(() => assert.fail('Should fail with ERROR_INVALID_CONFIGURATION'), (error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION)); }); test('errors cases - dirty', () => { instantiationService.stub(ITextFileService, 'isDirty', true); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }) .then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'), (error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY)); }); test('dirty error is not thrown if not asked to save', () => { instantiationService.stub(ITextFileService, 'isDirty', true); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotSave: true }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotSave: true }) .then(() => null, error => assert.fail('Should not fail.')); }); @@ -194,7 +194,7 @@ suite('ConfigurationEditingService', () => { instantiationService.stub(ITextFileService, 'isDirty', true); const target = sinon.stub(); instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: null, notify: null!, error: null!, info: null!, warn: null! }); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true }) .then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'), (error: ConfigurationEditingError) => { assert.equal(false, target.calledOnce); @@ -203,7 +203,7 @@ suite('ConfigurationEditingService', () => { }); test('write one setting - empty file', () => { - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }) .then(() => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); @@ -213,7 +213,7 @@ suite('ConfigurationEditingService', () => { test('write one setting - existing file', () => { fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value" }'); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }) .then(() => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); @@ -224,7 +224,7 @@ suite('ConfigurationEditingService', () => { test('remove an existing setting - existing file', () => { fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value", "configurationEditing.service.testSetting": "value" }'); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: undefined }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: undefined }) .then(() => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); @@ -235,7 +235,7 @@ suite('ConfigurationEditingService', () => { test('remove non existing setting - existing file', () => { fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value" }'); - return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: undefined }) + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: undefined }) .then(() => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); @@ -245,7 +245,7 @@ suite('ConfigurationEditingService', () => { }); test('write workspace standalone setting - empty file', () => { - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' }) .then(() => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']); const contents = fs.readFileSync(target).toString('utf8'); @@ -257,7 +257,7 @@ suite('ConfigurationEditingService', () => { test('write workspace standalone setting - existing file', () => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['launch']); fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }'); - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'launch.service.testSetting', value: 'value' }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'launch.service.testSetting', value: 'value' }) .then(() => { const contents = fs.readFileSync(target).toString('utf8'); const parsed = json.parse(contents); @@ -267,7 +267,7 @@ suite('ConfigurationEditingService', () => { }); test('write workspace standalone setting - empty file - full JSON', () => { - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } }) .then(() => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']); const contents = fs.readFileSync(target).toString('utf8'); @@ -281,7 +281,7 @@ suite('ConfigurationEditingService', () => { test('write workspace standalone setting - existing file - full JSON', () => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']); fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }'); - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } }) .then(() => { const contents = fs.readFileSync(target).toString('utf8'); const parsed = json.parse(contents); @@ -294,7 +294,7 @@ suite('ConfigurationEditingService', () => { test('write workspace standalone setting - existing file with JSON errors - full JSON', () => { const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']); fs.writeFileSync(target, '{ "my.super.setting": '); // invalid JSON - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } }) .then(() => { const contents = fs.readFileSync(target).toString('utf8'); const parsed = json.parse(contents); @@ -317,7 +317,7 @@ suite('ConfigurationEditingService', () => { } ] }`); - return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } }) + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } }) .then(() => { const actual = fs.readFileSync(target).toString('utf8'); const expected = JSON.stringify({ 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] }, null, '\t'); 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 dee633e4c90..0c3d0a6910d 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 @@ -730,6 +730,11 @@ suite('WorkspaceConfigurationService - Folder', () => { 'default': 'isSet', scope: ConfigurationScope.APPLICATION }, + 'configurationService.folder.machineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE + }, 'configurationService.folder.testSetting': { 'type': 'string', 'default': 'isSet', @@ -787,7 +792,7 @@ suite('WorkspaceConfigurationService - Folder', () => { }); test('defaults', () => { - assert.deepEqual(testObject.getValue('configurationService'), { 'folder': { 'applicationSetting': 'isSet', 'testSetting': 'isSet' } }); + assert.deepEqual(testObject.getValue('configurationService'), { 'folder': { 'applicationSetting': 'isSet', 'machineSetting': 'isSet', 'testSetting': 'isSet' } }); }); test('globals override defaults', () => { @@ -843,6 +848,13 @@ suite('WorkspaceConfigurationService - Folder', () => { .then(() => assert.equal(testObject.getValue('configurationService.folder.applicationSetting'), 'userValue')); }); + test('machine settings are not read from workspace', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.machineSetting": "userValue" }'); + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.machineSetting": "workspaceValue" }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('configurationService.folder.machineSetting'), 'userValue')); + }); + test('get application scope settings are not loaded after defaults are registered', () => { fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.anotherApplicationSetting": "workspaceValue" }'); return testObject.reloadConfiguration() @@ -862,6 +874,25 @@ suite('WorkspaceConfigurationService - Folder', () => { }); }); + test('get machine scope settings are not loaded after defaults are registered', () => { + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.anotherMachineSetting": "workspaceValue" }'); + return testObject.reloadConfiguration() + .then(() => { + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.folder.anotherMachineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE + } + } + }); + assert.deepEqual(testObject.keys().workspace, []); + }); + }); + test('reload configuration emits events after global configuraiton changes', () => { fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); const target = sinon.spy(); @@ -971,6 +1002,11 @@ suite('WorkspaceConfigurationService - Folder', () => { .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION)); }); + test('update machine setting into workspace configuration in a workspace is not supported', () => { + return testObject.updateValue('configurationService.folder.machineSetting', 'workspaceValue', {}, ConfigurationTarget.WORKSPACE, true) + .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE)); + }); + test('update tasks configuration', () => { return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, ConfigurationTarget.WORKSPACE) .then(() => assert.deepEqual(testObject.getValue('tasks'), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] })); @@ -1030,6 +1066,11 @@ suite('WorkspaceConfigurationService-Multiroot', () => { 'default': 'isSet', scope: ConfigurationScope.APPLICATION }, + 'configurationService.workspace.machineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE + }, 'configurationService.workspace.testResourceSetting': { 'type': 'string', 'default': 'isSet', @@ -1095,6 +1136,13 @@ suite('WorkspaceConfigurationService-Multiroot', () => { .then(() => assert.equal(testObject.getValue('configurationService.workspace.applicationSetting'), 'userValue')); }); + test('machine settings are not read from workspace', () => { + fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.machineSetting": "userValue" }'); + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.machineSetting': 'workspaceValue' } }, true) + .then(() => testObject.reloadConfiguration()) + .then(() => assert.equal(testObject.getValue('configurationService.workspace.machineSetting'), 'userValue')); + }); + test('workspace settings override user settings after defaults are registered ', () => { fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.newSetting": "userValue" }'); return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.newSetting': 'workspaceValue' } }, true) @@ -1121,6 +1169,13 @@ suite('WorkspaceConfigurationService-Multiroot', () => { .then(() => assert.equal(testObject.getValue('configurationService.workspace.applicationSetting'), 'userValue')); }); + test('machine settings are not read from workspace folder', () => { + fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.machineSetting": "userValue" }'); + fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.machineSetting": "workspaceFolderValue" }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('configurationService.workspace.machineSetting'), 'userValue')); + }); + test('application settings are not read from workspace folder after defaults are registered', () => { fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.testNewApplicationSetting": "userValue" }'); fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewApplicationSetting": "workspaceFolderValue" }'); @@ -1141,6 +1196,26 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }); }); + test('application settings are not read from workspace folder after defaults are registered', () => { + fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.testNewMachineSetting": "userValue" }'); + fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewMachineSetting": "workspaceFolderValue" }'); + return testObject.reloadConfiguration() + .then(() => { + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.workspace.testNewMachineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE + } + } + }); + assert.equal(testObject.getValue('configurationService.workspace.testNewMachineSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri }), 'userValue'); + }); + }); + test('resource setting in folder is read after it is registered later', () => { fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewResourceSetting2": "workspaceFolderValue" }'); return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.testNewResourceSetting2': 'workspaceValue' } }, true) @@ -1290,6 +1365,11 @@ suite('WorkspaceConfigurationService-Multiroot', () => { .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION)); }); + test('update machine setting into workspace configuration in a workspace is not supported', () => { + return testObject.updateValue('configurationService.workspace.machineSetting', 'workspaceValue', {}, ConfigurationTarget.WORKSPACE, true) + .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE)); + }); + test('update workspace folder configuration', () => { const workspace = workspaceContextService.getWorkspace(); return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER) diff --git a/src/vs/workbench/services/extensions/common/extensionHostDebug.ts b/src/vs/workbench/services/extensions/common/extensionHostDebug.ts index de19f9a2d9f..08d14adc775 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostDebug.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostDebug.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { IRemoteConsoleLog } from 'vs/base/common/console'; @@ -26,14 +25,22 @@ export interface ITerminateSessionEvent { subId?: string; } +export interface IReloadSessionEvent { + sessionId: string; +} + +export interface ICloseSessionEvent { + sessionId: string; +} + export interface IExtensionHostDebugService { _serviceBrand: any; - reload(resource: URI): void; - onReload: Event; + reload(sessionId: string): void; + onReload: Event; - close(resource: URI): void; - onClose: Event; + close(sessionId: string): void; + onClose: Event; attachSession(sessionId: string, port: number, subId?: string): void; onAttachSession: Event; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index f0a6ab8bccf..b215370499a 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -14,7 +14,6 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; -import { isEqual } from 'vs/base/common/resources'; import pkg from 'vs/platform/product/node/package'; import { URI } from 'vs/base/common/uri'; import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console'; @@ -96,13 +95,13 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._toDispose.push(this._onCrashed); this._toDispose.push(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e))); this._toDispose.push(this._lifecycleService.onShutdown(reason => this.terminate())); - this._toDispose.push(this._extensionHostDebugService.onClose(resource => { - if (this._isExtensionDevHost && this.matchesExtDevLocations(resource)) { + this._toDispose.push(this._extensionHostDebugService.onClose(event => { + if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._windowService.closeWindow(); } })); - this._toDispose.push(this._extensionHostDebugService.onReload(resource => { - if (this._isExtensionDevHost && this.matchesExtDevLocations(resource)) { + this._toDispose.push(this._extensionHostDebugService.onReload(event => { + if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._windowService.reloadWindow(); } })); @@ -114,16 +113,6 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { })); } - // returns true if the given resource url matches one of the extension development paths passed to VS Code - private matchesExtDevLocations(resource: URI): boolean { - - const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; - if (extDevLocs) { - return extDevLocs.some(extDevLoc => isEqual(extDevLoc, resource)); - } - return false; - } - public dispose(): void { this.terminate(); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts index a5e7a2dffd7..aa4a35f54dd 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts @@ -6,23 +6,20 @@ 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 } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { URI } from 'vs/base/common/uri'; +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'; -interface IReloadBroadcast { +interface IReloadBroadcast extends IReloadSessionEvent { type: 'vscode:extensionReload'; - resource: string; } interface IAttachSessionBroadcast extends IAttachSessionEvent { type: 'vscode:extensionAttach'; } -interface ICloseBroadcast { +interface ICloseBroadcast extends ICloseSessionEvent { type: 'vscode:extensionCloseExtensionHost'; - resource: string; } interface ILogToSessionBroadcast extends ILogToSessionEvent { @@ -39,8 +36,8 @@ class ExtensionHostDebugService implements IExtensionHostDebugService { _serviceBrand: any; private windowId: number; - private readonly _onReload = new Emitter(); - private readonly _onClose = new Emitter(); + 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(); @@ -53,10 +50,10 @@ class ExtensionHostDebugService implements IExtensionHostDebugService { ipc.on(CHANNEL, (_: unknown, broadcast: IReloadBroadcast | ICloseBroadcast | IAttachSessionBroadcast | ILogToSessionBroadcast | ITerminateSessionBroadcast) => { switch (broadcast.type) { case 'vscode:extensionReload': - this._onReload.fire(URI.parse(broadcast.resource)); + this._onReload.fire(broadcast); break; case 'vscode:extensionCloseExtensionHost': - this._onClose.fire(URI.parse(broadcast.resource)); + this._onClose.fire(broadcast); break; case 'vscode:extensionAttach': this._onAttachSession.fire(broadcast); @@ -71,25 +68,25 @@ class ExtensionHostDebugService implements IExtensionHostDebugService { }); } - reload(resource: URI): void { + reload(sessionId: string): void { ipc.send(CHANNEL, this.windowId, { type: 'vscode:extensionReload', - resource: resource.toString() + sessionId }); } - get onReload(): Event { + get onReload(): Event { return this._onReload.event; } - close(resource: URI): void { + close(sessionId: string): void { ipc.send(CHANNEL, this.windowId, { type: 'vscode:extensionCloseExtensionHost', - resource: resource.toString() + sessionId }); } - get onClose(): Event { + get onClose(): Event { return this._onClose.event; } diff --git a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts b/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts index 1a7fa42fec8..5d9270a6e6b 100644 --- a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts +++ b/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts @@ -19,7 +19,6 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens import { localize } from 'vs/nls'; import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; export class MultiExtensionManagementService extends Disposable implements IExtensionManagementService { @@ -35,8 +34,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); this.servers = this.extensionManagementServerService.remoteExtensionManagementServer ? [this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer] : [this.extensionManagementServerService.localExtensionManagementServer]; @@ -58,8 +56,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte if (!server) { return Promise.reject(`Invalid location ${extension.location.toString()}`); } - const syncExtensions = await this.hasToSyncExtensions(); - if (syncExtensions || isLanguagePackExtension(extension.manifest)) { + if (isLanguagePackExtension(extension.manifest)) { return this.uninstallEverywhere(extension, force); } return this.uninstallInServer(extension, server, force); @@ -134,9 +131,8 @@ export class MultiExtensionManagementService extends Disposable implements IExte async install(vsix: URI): Promise { if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const syncExtensions = await this.hasToSyncExtensions(); const manifest = await getManifest(vsix.fsPath); - if (syncExtensions || isLanguagePackExtension(manifest)) { + if (isLanguagePackExtension(manifest)) { // Install on both servers const [extensionIdentifier] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix))); return extensionIdentifier; @@ -156,9 +152,9 @@ export class MultiExtensionManagementService extends Disposable implements IExte async installFromGallery(gallery: IGalleryExtension): Promise { if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const [manifest, syncExtensions] = await Promise.all([this.extensionGalleryService.getManifest(gallery, CancellationToken.None), this.hasToSyncExtensions()]); + const manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None); if (manifest) { - if (syncExtensions || isLanguagePackExtension(manifest)) { + if (isLanguagePackExtension(manifest)) { // Install on both servers return Promise.all(this.servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(() => undefined); } @@ -199,17 +195,6 @@ export class MultiExtensionManagementService extends Disposable implements IExte private getServer(extension: ILocalExtension): IExtensionManagementServer | null { return this.extensionManagementServerService.getExtensionManagementServer(extension.location); } - - private async hasToSyncExtensions(): Promise { - if (!this.extensionManagementServerService.remoteExtensionManagementServer) { - return false; - } - const remoteEnv = await this.remoteAgentService.getEnvironment(); - if (!remoteEnv) { - return false; - } - return remoteEnv.syncExtensions; - } } registerSingleton(IExtensionManagementService, MultiExtensionManagementService); \ No newline at end of file diff --git a/src/vs/workbench/services/files2/test/node/diskFileService.test.ts b/src/vs/workbench/services/files2/test/node/diskFileService.test.ts index a4fb615b7de..5843fa18ebd 100644 --- a/src/vs/workbench/services/files2/test/node/diskFileService.test.ts +++ b/src/vs/workbench/services/files2/test/node/diskFileService.test.ts @@ -886,7 +886,8 @@ suite('Disk File Service', () => { assert.equal(fileStat.name, 'lorem.txt'); })); - assert.equal(readFileSync(resource.fsPath).toString(), '00000' + newContent); + const fileContent = readFileSync(resource.fsPath).toString(); + assert.ok(['0', '00', '000', '0000', '00000'].some(offset => fileContent === offset + newContent)); }); test('writeFile (readable)', async () => { diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index a5a3216f8e6..74ef7b96867 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { onUnexpectedError } from 'vs/base/common/errors'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; import { ITextEditorOptions, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IEditorInput, IEditor as IBaseEditor, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, Extensions as EditorInputExtensions, IFileInputFactory, IEditorIdentifier } from 'vs/workbench/common/editor'; @@ -888,7 +888,7 @@ export class HistoryService extends Disposable implements IHistoryService { // File resource: via URI.revive() if (serializedEditorHistoryEntry.resourceJSON) { - return { resource: URI.revive(serializedEditorHistoryEntry.resourceJSON) }; + return { resource: URI.revive(serializedEditorHistoryEntry.resourceJSON) }; } // Editor input: via factory @@ -974,4 +974,4 @@ export class HistoryService extends Disposable implements IHistoryService { } } -registerSingleton(IHistoryService, HistoryService); \ No newline at end of file +registerSingleton(IHistoryService, HistoryService); diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index 18e3fdaf601..ffc63601409 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -211,7 +211,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding return this.fileService.exists(this.resource) .then(exists => { const EOL = this.configurationService.getValue('files', { overrideIdentifier: 'json' })['eol']; - const result: Promise = exists ? Promise.resolve(null) : this.textFileService.write(this.resource, this.getEmptyContent(EOL)); + const result: Promise = exists ? Promise.resolve(null) : this.textFileService.write(this.resource, this.getEmptyContent(EOL), { encoding: 'utf8' }); return result.then(() => this.textModelResolverService.createModelReference(this.resource)); }); } diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index ff35157ee90..7546a8f0efe 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -215,10 +215,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic } async openRemoteSettings(): Promise { - const environemnt = await this.remoteAgentService.getEnvironment(); - if (environemnt) { - await this.createIfNotExists(environemnt.settingsPath, emptyEditableSettingsContent); - return this.editorService.openEditor({ resource: environemnt.settingsPath, options: { pinned: true, revealIfOpened: true } }); + const environment = await this.remoteAgentService.getEnvironment(); + if (environment) { + await this.createIfNotExists(environment.settingsPath, emptyEditableSettingsContent); + return this.editorService.openEditor({ resource: environment.settingsPath, options: { pinned: true, revealIfOpened: true } }); } return null; } @@ -520,6 +520,9 @@ export class PreferencesService extends Disposable implements IPreferencesServic private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI | null { switch (configurationTarget) { case ConfigurationTarget.USER: + case ConfigurationTarget.USER_LOCAL: + return URI.file(this.environmentService.appSettingsPath); + case ConfigurationTarget.USER_REMOTE: return URI.file(this.environmentService.appSettingsPath); case ConfigurationTarget.WORKSPACE: if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index 7385ab31222..5c7b5e91166 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -213,7 +213,7 @@ export interface IPreferencesService { export function getSettingsTargetName(target: ConfigurationTarget, resource: URI, workspaceContextService: IWorkspaceContextService): string { switch (target) { - case ConfigurationTarget.USER: + case ConfigurationTarget.USER_LOCAL: return localize('userSettingsTarget', "User Settings"); case ConfigurationTarget.WORKSPACE: return localize('workspaceSettingsTarget', "Workspace Settings"); diff --git a/src/vs/workbench/services/progress/browser/progressService2.ts b/src/vs/workbench/services/progress/browser/progressService2.ts index 80b1631c225..8f3203c675e 100644 --- a/src/vs/workbench/services/progress/browser/progressService2.ts +++ b/src/vs/workbench/services/progress/browser/progressService2.ts @@ -16,6 +16,10 @@ import { INotificationService, Severity, INotificationHandle, INotificationActio import { Action } from 'vs/base/common/actions'; import { Event } from 'vs/base/common/event'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; +import { Dialog } from 'vs/base/browser/ui/dialog/dialog'; +import { attachDialogStyler } from 'vs/platform/theme/common/styler'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; export class ProgressService2 implements IProgressService2 { @@ -29,6 +33,8 @@ export class ProgressService2 implements IProgressService2 { @IViewletService private readonly _viewletService: IViewletService, @INotificationService private readonly _notificationService: INotificationService, @IStatusbarService private readonly _statusbarService: IStatusbarService, + @ILayoutService private readonly _layoutService: ILayoutService, + @IThemeService private readonly _themeService: IThemeService ) { } withProgress(options: IProgressOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise { @@ -53,6 +59,8 @@ export class ProgressService2 implements IProgressService2 { return this._withViewletProgress('workbench.view.scm', task); case ProgressLocation.Extensions: return this._withViewletProgress('workbench.view.extensions', task); + case ProgressLocation.Dialog: + return this._withDialogProgress(options, task, onDidCancel); default: return Promise.reject(new Error(`Bad progress location: ${location}`)); } @@ -265,6 +273,52 @@ export class ProgressService2 implements IProgressService2 { promise.then(onDone, onDone); return promise; } + + private _withDialogProgress

, R = unknown>(options: IProgressOptions, task: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { + const disposables: IDisposable[] = []; + + let dialog: Dialog; + + const createDialog = (message: string) => { + dialog = new Dialog( + this._layoutService.container, + message, + [options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")], + { type: 'pending' } + ); + + disposables.push(dialog); + disposables.push(attachDialogStyler(dialog, this._themeService)); + + dialog.show().then(() => { + if (options.cancellable && typeof onDidCancel === 'function') { + onDidCancel(); + } + + dispose(dialog); + }); + + return dialog; + }; + + const updateDialog = (message?: string) => { + if (message && !dialog) { + dialog = createDialog(message); + } + }; + + const p = task({ + report: progress => { + updateDialog(progress.message); + } + }); + + p.finally(() => { + dispose(disposables); + }); + + return p; + } } registerSingleton(IProgressService2, ProgressService2, true); diff --git a/src/vs/workbench/services/textfile/test/fixtures/some_big5.txt b/src/vs/workbench/services/textfile/test/fixtures/some_big5.txt new file mode 100644 index 00000000000..b9e2570fef9 --- /dev/null +++ b/src/vs/workbench/services/textfile/test/fixtures/some_big5.txt @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/test/fixtures/some_cp1252.txt b/src/vs/workbench/services/textfile/test/fixtures/some_cp1252.txt new file mode 100644 index 00000000000..2ea52dc709f --- /dev/null +++ b/src/vs/workbench/services/textfile/test/fixtures/some_cp1252.txt @@ -0,0 +1,3 @@ +ObjectCount = LoadObjects("ffentlicher Ordner"); + +Private = "Persnliche Information" diff --git a/src/vs/workbench/services/textfile/test/fixtures/some_cyrillic.txt b/src/vs/workbench/services/textfile/test/fixtures/some_cyrillic.txt new file mode 100644 index 00000000000..f8ee3066712 --- /dev/null +++ b/src/vs/workbench/services/textfile/test/fixtures/some_cyrillic.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/test/fixtures/some_gbk.txt b/src/vs/workbench/services/textfile/test/fixtures/some_gbk.txt new file mode 100644 index 00000000000..eab73d1951b --- /dev/null +++ b/src/vs/workbench/services/textfile/test/fixtures/some_gbk.txt @@ -0,0 +1 @@ +йabc \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/test/fixtures/some_shiftjs.txt b/src/vs/workbench/services/textfile/test/fixtures/some_shiftjs.txt new file mode 100644 index 00000000000..efa955b3ecb --- /dev/null +++ b/src/vs/workbench/services/textfile/test/fixtures/some_shiftjs.txt @@ -0,0 +1 @@ +abc \ No newline at end of file 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 da7fc8d1c4e..65b968a90c3 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts @@ -9,7 +9,7 @@ import { workbenchInstantiationService, TestLifecycleService, TestTextFileServic import { IWindowsService } from 'vs/platform/windows/common/windows'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IFileService, ITextSnapshot, snapshotToString, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files'; +import { IFileService, ITextSnapshot, snapshotToString } from 'vs/platform/files/common/files'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -31,6 +31,7 @@ import { NodeTextFileService, EncodingOracle, IEncodingOverride } from 'vs/workb import { LegacyFileService } from 'vs/workbench/services/files/node/fileService'; import { DefaultEndOfLine } from 'vs/editor/common/model'; import { TextModel } from 'vs/editor/common/model/textModel'; +import { isWindows } from 'vs/base/common/platform'; class ServiceAccessor { constructor( @@ -248,7 +249,43 @@ suite('Files - TextFileService i/o', () => { const resolved = await service.resolve(resource); assert.equal(resolved.encoding, encoding); - assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.LF).createSnapshot(false)), expectedContent); + assert.equal(snapshotToString(resolved.value.create(isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(false)), expectedContent); + } + + test('write - use encoding (cp1252)', async () => { + await testEncodingKeepsData(URI.file(join(testDir, 'some_cp1252.txt')), 'cp1252', ['ObjectCount = LoadObjects("Öffentlicher Ordner");', '', 'Private = "Persönliche Information"', ''].join(isWindows ? '\r\n' : '\n')); + }); + + test('write - use encoding (shiftjis)', async () => { + await testEncodingKeepsData(URI.file(join(testDir, 'some_shiftjs.txt')), 'shiftjis', '中文abc'); + }); + + test('write - use encoding (gbk)', async () => { + await testEncodingKeepsData(URI.file(join(testDir, 'some_gbk.txt')), 'gbk', '中国abc'); + }); + + test('write - use encoding (cyrillic)', async () => { + await testEncodingKeepsData(URI.file(join(testDir, 'some_cyrillic.txt')), 'cp866', 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя'); + }); + + test('write - use encoding (big5)', async () => { + await testEncodingKeepsData(URI.file(join(testDir, 'some_big5.txt')), 'cp950', '中文abc'); + }); + + async function testEncodingKeepsData(resource: URI, encoding: string, expected: string) { + let resolved = await service.resolve(resource, { encoding }); + const content = snapshotToString(resolved.value.create(isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(content, expected); + + await service.write(resource, content, { encoding }); + + resolved = await service.resolve(resource, { encoding }); + assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.CRLF).createSnapshot(false)), content); + + await service.write(resource, TextModel.createFromString(content).createSnapshot(), { encoding }); + + resolved = await service.resolve(resource, { encoding }); + assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.CRLF).createSnapshot(false)), content); } test('write - no encoding - content as string', async () => { @@ -259,7 +296,7 @@ suite('Files - TextFileService i/o', () => { await service.write(resource, content); const resolved = await service.resolve(resource); - assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.LF).createSnapshot(false)), content); + assert.equal(snapshotToString(resolved.value.create(isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(false)), content); }); test('write - no encoding - content as snapshot', async () => { @@ -270,7 +307,7 @@ suite('Files - TextFileService i/o', () => { await service.write(resource, TextModel.createFromString(content).createSnapshot()); const resolved = await service.resolve(resource); - assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.LF).createSnapshot(false)), content); + assert.equal(snapshotToString(resolved.value.create(isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(false)), content); }); test('write - encoding preserved (UTF 16 LE) - content as string', async () => { @@ -358,50 +395,6 @@ suite('Files - TextFileService i/o', () => { assert.equal(detectedEncoding, UTF8); }); - test('write - CP1252 - content as string', async () => { - const resource = URI.file(join(testDir, 'small_umlaut.txt')); - - const content = (await readFile(resource.fsPath)).toString(); - - await service.write(resource, content, { encoding: 'cp1252' }); - - const resolved = await service.resolve(resource, { encoding: 'cp1252' }); - assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.LF).createSnapshot(false)), content); - }); - - test('write - all encodings - large content as snapshot', async () => { - const resource = URI.file(join(testDir, 'lorem.txt')); - const content = (await readFile(resource.fsPath)).toString(); - - for (const encoding of Object.keys(SUPPORTED_ENCODINGS)) { - if (encoding === 'utf8bom') { - continue; // this is the only encoding that is not standard, so skip it - } - - await testEncoding2(resource, encoding, content); - } - }); - - test('write - all encodings - small content as snapshot', async () => { - const resource = URI.file(join(testDir, 'small.txt')); - const content = (await readFile(resource.fsPath)).toString(); - - for (const encoding of Object.keys(SUPPORTED_ENCODINGS)) { - if (encoding === 'utf8bom') { - continue; // this is the only encoding that is not standard, so skip it - } - - await testEncoding2(resource, encoding, content); - } - }); - - async function testEncoding2(resource: URI, encoding: string, content: string): Promise { - await service.write(resource, content, { encoding }); - - const resolved = await service.resolve(resource, { encoding }); - assert.equal(snapshotToString(resolved.value.create(DefaultEndOfLine.LF).createSnapshot(false)), content, 'Encoding used: ' + encoding); - } - test('write - ensure BOM in empty file - content as string', async () => { const resource = URI.file(join(testDir, 'small.txt')); diff --git a/yarn.lock b/yarn.lock index f92d2434817..86a0865607c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9541,10 +9541,10 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" -vscode-xterm@3.13.0-beta2: - version "3.13.0-beta2" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.13.0-beta2.tgz#4517a96ef30d8a8d6f27c60bfc374a405811ee6e" - integrity sha512-9iu3oxpFbyUzsAPYeipMSaI7I/nY4WHlpq2kJXXzibZAO9l7pVFBxFR9H0gfDBVn1+fMJsLIzRWGX9lKC83lfQ== +vscode-xterm@3.13.0-beta3: + version "3.13.0-beta3" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.13.0-beta3.tgz#ab642ed77df07c2adfca7b15ae39c18328db3fc6" + integrity sha512-XvgD/P6CCV0+79UYM7CEL6Ziv2RiDopI3Wa1hIm3Dm8InWxkl3QwykINlempMNub+r0gwVwLKSQYr+Q/jg1IAw== vso-node-api@6.1.2-preview: version "6.1.2-preview"