diff --git a/.github/classifier.yml b/.github/classifier.yml index dbdd23ddfb7..a83c95ad2ba 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -10,7 +10,7 @@ color-picker: [], css-less-sass: [ aeschli ], debug: { - assignees: [ isidorn ], + assignees: [ weinand ], assignLabel: false }, diff-editor: [], @@ -35,15 +35,15 @@ error-list: [], extensions: [], file-encoding: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, file-io: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, file-watcher: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, file-explorer: { @@ -65,7 +65,7 @@ markdown: [ mjbvz ], merge-conflict: [ chrmarti ], multi-root: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, perf-profile: [], @@ -86,59 +86,59 @@ themes: [], typescript: [ mjbvz ], workbench: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-dnd: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-editors: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-electron: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-feedback: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-history: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-layout: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-menu: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-notifications: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-state: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-status: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-tabs: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-title: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-touchbar: { - assignees: [ bpasero ], + assignees: [], assignLabel: false }, workbench-welcome: [ chrmarti ] diff --git a/.travis.yml b/.travis.yml index 693cdcbb4d1..cb271784ad9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,8 +33,6 @@ addons: before_install: - export GITHUB_TOKEN=$PUBLIC_GITHUB_TOKEN - git submodule update --init --recursive - - git clone --depth 1 https://github.com/creationix/nvm.git ./.nvm - - source ./.nvm/nvm.sh - nvm install 8.9.1 - nvm use 8.9.1 - npm i -g yarn diff --git a/.vscode/launch.json b/.vscode/launch.json index 8160fb09320..5b9bd2fff8b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -165,12 +165,12 @@ "name": "VS Code Markdown Extension Tests", "runtimeExecutable": "${execPath}", "args": [ - "${workspaceFolder}/extensions/markdown/test-fixtures", - "--extensionDevelopmentPath=${workspaceFolder}/extensions/markdown", - "--extensionTestsPath=${workspaceFolder}/extensions/markdown/out/test" + "${workspaceFolder}/extensions/markdown-language-features/test-fixtures", + "--extensionDevelopmentPath=${workspaceFolder}/extensions/markdown-language-features", + "--extensionTestsPath=${workspaceFolder}/extensions/markdown-language-features/out/test" ], "outFiles": [ - "${workspaceFolder}/extensions/markdown/out/**/*.js" + "${workspaceFolder}/extensions/markdown-language-features/out/**/*.js" ] }, { diff --git a/.vscode/settings.json b/.vscode/settings.json index d5e5d8c85a7..e2bd13950ea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,5 @@ { "editor.insertSpaces": false, - "files.eol": "\n", "files.trimTrailingWhitespace": true, "files.exclude": { ".git": true, diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index ac3baed691a..ddd3c9e44be 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,12 +1,12 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.22.5", + "version": "1.22.11", "repo": "https://github.com/Microsoft/vscode-node-debug" }, { "name": "ms-vscode.node-debug2", - "version": "1.22.2", + "version": "1.22.5", "repo": "https://github.com/Microsoft/vscode-node-debug2" } ] \ No newline at end of file diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 201f9c2c32c..6b4cdd2855f 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -82,7 +82,7 @@ const indentationFilter = [ '!build/**/*.sh', '!build/tfs/**/*.js', '!**/Dockerfile', - '!extensions/markdown/media/*.js' + '!extensions/markdown-language-features/media/*.js' ]; const copyrightFilter = [ @@ -104,8 +104,9 @@ const copyrightFilter = [ '!build/**/*.init', '!resources/linux/snap/snapcraft.yaml', '!resources/win32/bin/code.js', - '!extensions/markdown/media/tomorrow.css', - '!extensions/html-language-features/server/src/modes/typescript/*' + '!extensions/markdown-language-features/media/tomorrow.css', + '!extensions/html-language-features/server/src/modes/typescript/*', + '!extensions/*/server/bin/*' ]; const eslintFilter = [ diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 31282b6c5bb..6f5558001c4 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -1046,7 +1046,10 @@ function createI18nFile(originalFilePath, messages) { var key = _a[_i]; result[key] = messages[key]; } - var content = JSON.stringify(result, null, '\t').replace(/\r\n/g, '\n'); + var content = JSON.stringify(result, null, '\t'); + if (process.platform === 'win32') { + content = content.replace(/\n/g, '\r\n'); + } return new File({ path: path.join(originalFilePath + '.i18n.json'), contents: Buffer.from(content, 'utf8') diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 7c5899ac953..06b51be8767 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -1171,7 +1171,10 @@ function createI18nFile(originalFilePath: string, messages: any): File { result[key] = messages[key]; } - let content = JSON.stringify(result, null, '\t').replace(/\r\n/g, '\n'); + let content = JSON.stringify(result, null, '\t'); + if (process.platform === 'win32') { + content = content.replace(/\n/g, '\r\n'); + } return new File({ path: path.join(originalFilePath + '.i18n.json'), contents: Buffer.from(content, 'utf8') diff --git a/build/monaco/package.json b/build/monaco/package.json index 71492a669fa..958b4ee71c3 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.11.6", + "version": "0.11.7", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", diff --git a/build/tfs/product-build.yml b/build/tfs/product-build.yml index 5becec89bca..f0e6f2811a3 100644 --- a/build/tfs/product-build.yml +++ b/build/tfs/product-build.yml @@ -55,11 +55,11 @@ phases: "parameters": [ { "parameterName": "OpusName", - "parameterValue": "Microsoft" + "parameterValue": "VS Code" }, { "parameterName": "OpusInfo", - "parameterValue": "http://www.microsoft.com" + "parameterValue": "https://code.visualstudio.com/" }, { "parameterName": "PageHash", @@ -79,11 +79,11 @@ phases: "parameters": [ { "parameterName": "OpusName", - "parameterValue": "Microsoft" + "parameterValue": "VS Code" }, { "parameterName": "OpusInfo", - "parameterValue": "http://www.microsoft.com" + "parameterValue": "https://code.visualstudio.com/" }, { "parameterName": "Append", @@ -137,11 +137,11 @@ phases: "parameters": [ { "parameterName": "OpusName", - "parameterValue": "Microsoft" + "parameterValue": "VS Code" }, { "parameterName": "OpusInfo", - "parameterValue": "http://www.microsoft.com" + "parameterValue": "https://code.visualstudio.com/" }, { "parameterName": "PageHash", @@ -161,11 +161,11 @@ phases: "parameters": [ { "parameterName": "OpusName", - "parameterValue": "Microsoft" + "parameterValue": "VS Code" }, { "parameterName": "OpusInfo", - "parameterValue": "http://www.microsoft.com" + "parameterValue": "https://code.visualstudio.com/" }, { "parameterName": "Append", @@ -224,78 +224,58 @@ phases: - phase: Linux condition: eq(variables['VSCODE_BUILD_LINUX'], 'true') - queue: - name: Hosted Linux Preview - parallel: 2 - matrix: - x64: - VSCODE_ARCH: x64 - ia32: - VSCODE_ARCH: ia32 + queue: linux-x64 + variables: + VSCODE_ARCH: x64 steps: + - task: NodeTool@0 + inputs: + versionSpec: "8.9.1" + + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.3.2" + - script: | - # dependencies - dpkg --add-architecture i386 - apt-get update - - DEPS=" \ - gcc-multilib g++-multilib \ - pkg-config \ - dbus \ - xvfb \ - fakeroot \ - bc \ - bsdmainutils \ - rpm \ - " - - if [[ "$(VSCODE_ARCH)" == "x64" ]]; then - DEPS="$DEPS \ - dpkg-dev \ - libgconf-2-4 \ - libnss3 \ - libasound2 \ - libxtst6 \ - libx11-dev \ - libxkbfile-dev \ - libxss1 \ - libx11-xcb-dev \ - libsecret-1-dev \ - " - else - DEPS="$DEPS \ - dpkg-dev:i386 \ - libgconf-2-4:i386 \ - libnss3:i386 \ - libasound2:i386 \ - libxtst6:i386 \ - libnotify4:i386 \ - libx11-dev:i386 \ - libxkbfile-dev:i386 \ - libxss1:i386 \ - libx11-xcb-dev:i386 \ - libgl1-mesa-glx:i386 libgl1-mesa-dri:i386 \ - libgirepository-1.0-1:i386 \ - gir1.2-glib-2.0:i386 \ - gir1.2-secret-1:i386 \ - libsecret-1-dev:i386 \ - libgtk2.0-0:i386 \ - " + export npm_config_arch="$(VSCODE_ARCH)" + if [[ "$(VSCODE_ARCH)" == "ia32" ]]; then + export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig" fi - apt-get install -y $DEPS + echo "machine monacotools.visualstudio.com password $(VSO_PAT)" > ~/.netrc + yarn + npm run gulp -- hygiene + npm run monaco-compile-check + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin + node build/tfs/common/installDistro.js - # setup xvfb - cp build/tfs/linux/$(VSCODE_ARCH)/xvfb.init /etc/init.d/xvfb - chmod +x /etc/init.d/xvfb - update-rc.d xvfb defaults - service xvfb start + - script: | + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min + name: build - # setup dbus - ln -sf /bin/dbus-daemon /usr/bin/dbus-daemon - service dbus start + - script: | + npm run gulp -- "electron-$(VSCODE_ARCH)" + DISPLAY=:10 ./scripts/test.sh --build --tfs + name: test + - script: | + npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-deb" + npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-rpm" + #npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-snap" + + AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ + MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \ + ./build/tfs/linux/release2.sh "$(VSCODE_ARCH)" "$(LINUX_REPO_PASSWORD)" + +- phase: Linux32 + condition: eq(variables['VSCODE_BUILD_LINUX'], 'true') + queue: linux-ia32 + variables: + VSCODE_ARCH: ia32 + + steps: - task: NodeTool@0 inputs: versionSpec: "8.9.1" diff --git a/build/win32/OSSREADME.json b/build/win32/OSSREADME.json index cbcef582e54..10f47d06684 100755 --- a/build/win32/OSSREADME.json +++ b/build/win32/OSSREADME.json @@ -1,10 +1,10 @@ [ { - "name": "rust-lang-nursery/lazy-static.rs", - "version": "1.0.0", - "repositoryUrl": "https://github.com/rust-lang-nursery/lazy-static.rs", + "name": "rust-lang/libc", + "version": "0.2.36", + "repositoryUrl": "https://github.com/rust-lang/libc", "licenseDetail": [ - "Copyright (c) 2010 The Rust Project Developers", + "Copyright (c) 2014 The Rust Project Developers", "", "Permission is hereby granted, free of charge, to any", "person obtaining a copy of this software and associated", @@ -32,6 +32,33 @@ ], "isProd": true }, + { + "name": "retep998/winapi-rs", + "version": "0.4.0", + "repositoryUrl": "https://github.com/retep998/winapi-rs", + "licenseDetail": [ + "Copyright (c) 2015 The winapi-rs Developers", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", + "SOFTWARE." + ], + "isProd": true + }, { "name": "rust-num/num", "version": "0.1.41", @@ -65,6 +92,35 @@ ], "isProd": true }, + { + "name": "BurntSushi/byteorder", + "version": "1.2.1", + "repositoryUrl": "https://github.com/BurntSushi/byteorder", + "licenseDetail": [ + "The MIT License (MIT)", + "", + "Copyright (c) 2015 Andrew Gallant", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in", + "all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN", + "THE SOFTWARE." + ], + "isProd": true + }, { "name": "dtolnay/isatty", "version": "0.1.6", @@ -98,6 +154,72 @@ ], "isProd": true }, + { + "name": "rust-lang-nursery/lazy-static.rs", + "version": "1.0.0", + "repositoryUrl": "https://github.com/rust-lang-nursery/lazy-static.rs", + "licenseDetail": [ + "Copyright (c) 2010 The Rust Project Developers", + "", + "Permission is hereby granted, free of charge, to any", + "person obtaining a copy of this software and associated", + "documentation files (the \"Software\"), to deal in the", + "Software without restriction, including without", + "limitation the rights to use, copy, modify, merge,", + "publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software", + "is furnished to do so, subject to the following", + "conditions:", + "", + "The above copyright notice and this permission notice", + "shall be included in all copies or substantial portions", + "of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", + "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", + "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", + "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", + "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", + "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", + "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", + "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", + "DEALINGS IN THE SOFTWARE." + ], + "isProd": true + }, + { + "name": "rust-num/num-integer", + "version": "0.1.35", + "repositoryUrl": "https://github.com/rust-num/num-integer", + "licenseDetail": [ + "Copyright (c) 2014 The Rust Project Developers", + "", + "Permission is hereby granted, free of charge, to any", + "person obtaining a copy of this software and associated", + "documentation files (the \"Software\"), to deal in the", + "Software without restriction, including without", + "limitation the rights to use, copy, modify, merge,", + "publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software", + "is furnished to do so, subject to the following", + "conditions:", + "", + "The above copyright notice and this permission notice", + "shall be included in all copies or substantial portions", + "of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", + "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", + "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", + "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", + "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", + "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", + "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", + "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", + "DEALINGS IN THE SOFTWARE." + ], + "isProd": true + }, { "name": "retep998/winapi-rs", "version": "0.2.2", @@ -126,100 +248,9 @@ "isProd": true }, { - "name": "BurntSushi/byteorder", - "version": "1.2.1", - "repositoryUrl": "https://github.com/BurntSushi/byteorder", - "licenseDetail": [ - "The MIT License (MIT)", - "", - "Copyright (c) 2015 Andrew Gallant", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in", - "all copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN", - "THE SOFTWARE." - ], - "isProd": true - }, - { - "name": "rust-num/num-integer", - "version": "0.1.35", - "repositoryUrl": "https://github.com/rust-num/num-integer", - "licenseDetail": [ - "Copyright (c) 2014 The Rust Project Developers", - "", - "Permission is hereby granted, free of charge, to any", - "person obtaining a copy of this software and associated", - "documentation files (the \"Software\"), to deal in the", - "Software without restriction, including without", - "limitation the rights to use, copy, modify, merge,", - "publish, distribute, sublicense, and/or sell copies of", - "the Software, and to permit persons to whom the Software", - "is furnished to do so, subject to the following", - "conditions:", - "", - "The above copyright notice and this permission notice", - "shall be included in all copies or substantial portions", - "of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", - "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", - "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", - "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", - "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", - "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", - "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", - "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", - "DEALINGS IN THE SOFTWARE." - ], - "isProd": true - }, - { - "name": "mrhooray/crc-rs", - "version": "1.7.0", - "repositoryUrl": "https://github.com/mrhooray/crc-rs.git", - "licenseDetail": [ - "MIT License", - "", - "Copyright (c) 2017 crc-rs Developers", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all", - "copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", - "SOFTWARE." - ], - "isProd": true - }, - { - "name": "rust-lang/libc", - "version": "0.2.36", - "repositoryUrl": "https://github.com/rust-lang/libc", + "name": "rust-num/num-iter", + "version": "0.1.34", + "repositoryUrl": "https://github.com/rust-num/num-iter", "licenseDetail": [ "Copyright (c) 2014 The Rust Project Developers", "", @@ -283,9 +314,9 @@ "isProd": true }, { - "name": "rust-num/num-iter", - "version": "0.1.34", - "repositoryUrl": "https://github.com/rust-num/num-iter", + "name": "slog-rs/slog", + "version": "2.1.1", + "repositoryUrl": "https://github.com/slog-rs/slog", "licenseDetail": [ "Copyright (c) 2014 The Rust Project Developers", "", @@ -316,35 +347,60 @@ "isProd": true }, { - "name": "slog-rs/slog", - "version": "2.1.1", - "repositoryUrl": "https://github.com/slog-rs/slog", + "name": "Sgeo/take_mut", + "version": "0.2.0", + "repositoryUrl": "https://github.com/Sgeo/take_mut", "licenseDetail": [ - "Copyright (c) 2014 The Rust Project Developers", + "The MIT License (MIT)", "", - "Permission is hereby granted, free of charge, to any", - "person obtaining a copy of this software and associated", - "documentation files (the \"Software\"), to deal in the", - "Software without restriction, including without", - "limitation the rights to use, copy, modify, merge,", - "publish, distribute, sublicense, and/or sell copies of", - "the Software, and to permit persons to whom the Software", - "is furnished to do so, subject to the following", - "conditions:", + "Copyright (c) 2016 Sgeo", "", - "The above copyright notice and this permission notice", - "shall be included in all copies or substantial portions", - "of the Software.", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", - "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", - "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", - "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", - "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", - "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", - "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", - "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", - "DEALINGS IN THE SOFTWARE." + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", + "SOFTWARE." + ], + "isProd": true + }, + { + "name": "redox-os/termios", + "version": "0.1.1", + "repositoryUrl": "https://github.com/redox-os/termios", + "licenseDetail": [ + "MIT License", + "", + "Copyright (c) 2017 Redox OS", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", + "SOFTWARE." ], "isProd": true }, @@ -379,75 +435,13 @@ "isProd": true }, { - "name": "Stebalien/term", - "version": "0.4.6", - "repositoryUrl": "https://github.com/Stebalien/term", - "licenseDetail": [ - "Copyright (c) 2014 The Rust Project Developers", - "", - "Permission is hereby granted, free of charge, to any", - "person obtaining a copy of this software and associated", - "documentation files (the \"Software\"), to deal in the", - "Software without restriction, including without", - "limitation the rights to use, copy, modify, merge,", - "publish, distribute, sublicense, and/or sell copies of", - "the Software, and to permit persons to whom the Software", - "is furnished to do so, subject to the following", - "conditions:", - "", - "The above copyright notice and this permission notice", - "shall be included in all copies or substantial portions", - "of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", - "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", - "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", - "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", - "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", - "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", - "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", - "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", - "DEALINGS IN THE SOFTWARE." - ], - "isProd": true - }, - { - "name": "redox-os/termios", - "version": "0.1.1", - "repositoryUrl": "https://github.com/redox-os/termios", + "name": "mrhooray/crc-rs", + "version": "1.7.0", + "repositoryUrl": "https://github.com/mrhooray/crc-rs.git", "licenseDetail": [ "MIT License", "", - "Copyright (c) 2017 Redox OS", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all", - "copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", - "SOFTWARE." - ], - "isProd": true - }, - { - "name": "Sgeo/take_mut", - "version": "0.2.0", - "repositoryUrl": "https://github.com/Sgeo/take_mut", - "licenseDetail": [ - "The MIT License (MIT)", - "", - "Copyright (c) 2016 Sgeo", + "Copyright (c) 2017 crc-rs Developers", "", "Permission is hereby granted, free of charge, to any person obtaining a copy", "of this software and associated documentation files (the \"Software\"), to deal", @@ -560,39 +554,6 @@ ], "isProd": true }, - { - "name": "rust-lang/time", - "version": "0.1.39", - "repositoryUrl": "https://github.com/rust-lang/time", - "licenseDetail": [ - "Copyright (c) 2014 The Rust Project Developers", - "", - "Permission is hereby granted, free of charge, to any", - "person obtaining a copy of this software and associated", - "documentation files (the \"Software\"), to deal in the", - "Software without restriction, including without", - "limitation the rights to use, copy, modify, merge,", - "publish, distribute, sublicense, and/or sell copies of", - "the Software, and to permit persons to whom the Software", - "is furnished to do so, subject to the following", - "conditions:", - "", - "The above copyright notice and this permission notice", - "shall be included in all copies or substantial portions", - "of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", - "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", - "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", - "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", - "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", - "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", - "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", - "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", - "DEALINGS IN THE SOFTWARE." - ], - "isProd": true - }, { "name": "chronotope/chrono", "version": "0.4.0", @@ -868,29 +829,35 @@ "isProd": true }, { - "name": "retep998/winapi-rs", - "version": "0.1.1", - "repositoryUrl": "https://github.com/retep998/winapi-rs", + "name": "rust-lang/time", + "version": "0.1.39", + "repositoryUrl": "https://github.com/rust-lang/time", "licenseDetail": [ - "Copyright (c) 2015 The winapi-rs Developers", + "Copyright (c) 2014 The Rust Project Developers", "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", + "Permission is hereby granted, free of charge, to any", + "person obtaining a copy of this software and associated", + "documentation files (the \"Software\"), to deal in the", + "Software without restriction, including without", + "limitation the rights to use, copy, modify, merge,", + "publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software", + "is furnished to do so, subject to the following", + "conditions:", "", - "The above copyright notice and this permission notice shall be included in all", - "copies or substantial portions of the Software.", + "The above copyright notice and this permission notice", + "shall be included in all copies or substantial portions", + "of the Software.", "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", - "SOFTWARE." + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", + "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", + "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", + "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", + "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", + "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", + "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", + "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", + "DEALINGS IN THE SOFTWARE." ], "isProd": true }, @@ -948,33 +915,6 @@ ], "isProd": true }, - { - "name": "retep998/winapi-rs", - "version": "0.4.0", - "repositoryUrl": "https://github.com/retep998/winapi-rs", - "licenseDetail": [ - "Copyright (c) 2015 The winapi-rs Developers", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all", - "copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", - "SOFTWARE." - ], - "isProd": true - }, { "name": "retep998/winapi-rs", "version": "0.3.4", @@ -1002,33 +942,6 @@ ], "isProd": true }, - { - "name": "retep998/winapi-rs", - "version": "0.4.0", - "repositoryUrl": "https://github.com/retep998/winapi-rs", - "licenseDetail": [ - "Copyright (c) 2015 The winapi-rs Developers", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all", - "copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", - "SOFTWARE." - ], - "isProd": true - }, { "name": "slog-rs/async", "version": "2.2.0", @@ -1790,5 +1703,92 @@ " defined by the Mozilla Public License, v. 2.0." ], "isProd": true + }, + { + "name": "retep998/winapi-rs", + "version": "0.1.1", + "repositoryUrl": "https://github.com/retep998/winapi-rs", + "licenseDetail": [ + "Copyright (c) 2015 The winapi-rs Developers", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", + "SOFTWARE." + ], + "isProd": true + }, + { + "name": "retep998/winapi-rs", + "version": "0.4.0", + "repositoryUrl": "https://github.com/retep998/winapi-rs", + "licenseDetail": [ + "Copyright (c) 2015 The winapi-rs Developers", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy", + "of this software and associated documentation files (the \"Software\"), to deal", + "in the Software without restriction, including without limitation the rights", + "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", + "copies of the Software, and to permit persons to whom the Software is", + "furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all", + "copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", + "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", + "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", + "SOFTWARE." + ], + "isProd": true + }, + { + "name": "Stebalien/term", + "version": "0.4.6", + "repositoryUrl": "https://github.com/Stebalien/term", + "licenseDetail": [ + "Copyright (c) 2014 The Rust Project Developers", + "", + "Permission is hereby granted, free of charge, to any", + "person obtaining a copy of this software and associated", + "documentation files (the \"Software\"), to deal in the", + "Software without restriction, including without", + "limitation the rights to use, copy, modify, merge,", + "publish, distribute, sublicense, and/or sell copies of", + "the Software, and to permit persons to whom the Software", + "is furnished to do so, subject to the following", + "conditions:", + "", + "The above copyright notice and this permission notice", + "shall be included in all copies or substantial portions", + "of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF", + "ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED", + "TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A", + "PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT", + "SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY", + "CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION", + "OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR", + "IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER", + "DEALINGS IN THE SOFTWARE." + ], + "isProd": true } ] diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index c216c404332..b69182a7e91 100755 Binary files a/build/win32/inno_updater.exe and b/build/win32/inno_updater.exe differ diff --git a/extensions/css/.vscode/launch.json b/extensions/css-language-features/.vscode/launch.json similarity index 80% rename from extensions/css/.vscode/launch.json rename to extensions/css-language-features/.vscode/launch.json index fa74c4170fc..68f7c70e450 100644 --- a/extensions/css/.vscode/launch.json +++ b/extensions/css-language-features/.vscode/launch.json @@ -1,5 +1,11 @@ { "version": "0.2.0", + "compounds": [ + { + "name": "Debug Extension and Language Server", + "configurations": ["Launch Extension", "Attach Language Server"] + } + ], "configurations": [ { "name": "Launch Extension", @@ -32,7 +38,8 @@ "protocol": "inspector", "port": 6044, "sourceMaps": true, - "outFiles": ["${workspaceFolder}/server/out/**/*.js"] + "outFiles": ["${workspaceFolder}/server/out/**/*.js"], + "restart": true } ] } \ No newline at end of file diff --git a/extensions/css/.vscode/tasks.json b/extensions/css-language-features/.vscode/tasks.json similarity index 100% rename from extensions/css/.vscode/tasks.json rename to extensions/css-language-features/.vscode/tasks.json diff --git a/extensions/css-language-features/.vscodeignore b/extensions/css-language-features/.vscodeignore new file mode 100644 index 00000000000..b85541d78ee --- /dev/null +++ b/extensions/css-language-features/.vscodeignore @@ -0,0 +1,5 @@ +client/src/** +client/tsconfig.json +server/src/** +server/tsconfig.json +server/node_modules/@types/** \ No newline at end of file diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts similarity index 57% rename from extensions/css/client/src/cssMain.ts rename to extensions/css-language-features/client/src/cssMain.ts index a8aaa53a18a..22285fb91bf 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -8,8 +8,9 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString } from 'vscode'; -import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient'; +import { languages, window, commands, ExtensionContext, Range, Position, TextDocument, CompletionItem, CompletionItemKind, TextEdit, SnippetString, FoldingRangeList, FoldingRange, FoldingContext, CancellationToken } from 'vscode'; +import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Disposable } from 'vscode-languageclient'; +import { FoldingRangesRequest, FoldingRangeRequestParam } from 'vscode-languageserver-protocol-foldingprovider'; // this method is called when vs code is activated export function activate(context: ExtensionContext) { @@ -67,31 +68,59 @@ export function activate(context: ExtensionContext) { indentationRules: indentationRules }); - const regionCompletionRegExpr = /^(\s*)(\/(\*\s*(#\w*)?)?)?$/; - languages.registerCompletionItemProvider(documentSelector, { - provideCompletionItems(doc, pos) { - let lineUntilPos = doc.getText(new Range(new Position(pos.line, 0), pos)); - let match = lineUntilPos.match(regionCompletionRegExpr); - if (match) { - let range = new Range(new Position(pos.line, match[1].length), pos); - let beginProposal = new CompletionItem('#region', CompletionItemKind.Snippet); - beginProposal.range = range; TextEdit.replace(range, '/* #region */'); - beginProposal.insertText = new SnippetString('/* #region $1*/'); - beginProposal.documentation = localize('folding.start', 'Folding Region Start'); - beginProposal.filterText = match[2]; - beginProposal.sortText = 'za'; - let endProposal = new CompletionItem('#endregion', CompletionItemKind.Snippet); - endProposal.range = range; - endProposal.insertText = '/* #endregion */'; - endProposal.documentation = localize('folding.end', 'Folding Region End'); - endProposal.sortText = 'zb'; - endProposal.filterText = match[2]; - return [beginProposal, endProposal]; - } - return null; - } + client.onReady().then(() => { + context.subscriptions.push(initCompletionProvider()); + context.subscriptions.push(initFoldingProvider()); }); + function initCompletionProvider(): Disposable { + const regionCompletionRegExpr = /^(\s*)(\/(\*\s*(#\w*)?)?)?$/; + + return languages.registerCompletionItemProvider(documentSelector, { + provideCompletionItems(doc, pos) { + let lineUntilPos = doc.getText(new Range(new Position(pos.line, 0), pos)); + let match = lineUntilPos.match(regionCompletionRegExpr); + if (match) { + let range = new Range(new Position(pos.line, match[1].length), pos); + let beginProposal = new CompletionItem('#region', CompletionItemKind.Snippet); + beginProposal.range = range; TextEdit.replace(range, '/* #region */'); + beginProposal.insertText = new SnippetString('/* #region $1*/'); + beginProposal.documentation = localize('folding.start', 'Folding Region Start'); + beginProposal.filterText = match[2]; + beginProposal.sortText = 'za'; + let endProposal = new CompletionItem('#endregion', CompletionItemKind.Snippet); + endProposal.range = range; + endProposal.insertText = '/* #endregion */'; + endProposal.documentation = localize('folding.end', 'Folding Region End'); + endProposal.sortText = 'zb'; + endProposal.filterText = match[2]; + return [beginProposal, endProposal]; + } + return null; + } + }); + } + + function initFoldingProvider(): Disposable { + return languages.registerFoldingProvider(documentSelector, { + provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { + const param: FoldingRangeRequestParam = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + maxRanges: context.maxRanges + }; + return client.sendRequest(FoldingRangesRequest.type, param, token).then(res => { + if (res && Array.isArray(res.ranges)) { + return new FoldingRangeList(res.ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.type))); + } + return null; + }, error => { + client.logFailedRequest(FoldingRangesRequest.type, error); + return null; + }); + } + }); + } + commands.registerCommand('_css.applyCodeAction', applyCodeAction); function applyCodeAction(uri: string, documentVersion: number, edits: TextEdit[]) { diff --git a/extensions/css/client/src/typings/ref.d.ts b/extensions/css-language-features/client/src/typings/ref.d.ts similarity index 100% rename from extensions/css/client/src/typings/ref.d.ts rename to extensions/css-language-features/client/src/typings/ref.d.ts diff --git a/extensions/css/client/tsconfig.json b/extensions/css-language-features/client/tsconfig.json similarity index 90% rename from extensions/css/client/tsconfig.json rename to extensions/css-language-features/client/tsconfig.json index ee67f8333d4..473f4e85fc9 100644 --- a/extensions/css/client/tsconfig.json +++ b/extensions/css-language-features/client/tsconfig.json @@ -4,6 +4,7 @@ "module": "commonjs", "outDir": "./out", "noUnusedLocals": true, + "sourceMap": true, "lib": [ "es2016" ], diff --git a/extensions/css/icons/css.png b/extensions/css-language-features/icons/css.png similarity index 100% rename from extensions/css/icons/css.png rename to extensions/css-language-features/icons/css.png diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json new file mode 100644 index 00000000000..34bfb1b799c --- /dev/null +++ b/extensions/css-language-features/package.json @@ -0,0 +1,702 @@ +{ + "name": "css-language-features", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.0", + "publisher": "vscode", + "engines": { + "vscode": "0.10.x" + }, + "icon": "icons/css.png", + "activationEvents": [ + "onLanguage:css", + "onLanguage:less", + "onLanguage:scss", + "onCommand:_css.applyCodeAction" + ], + "enableProposedApi": true, + "main": "./client/out/cssMain", + "scripts": { + "compile": "gulp compile-extension:css-language-features-client & gulp compile-extension:css-language-features-server", + "postinstall": "cd server && yarn install", + "install-client-next": "yarn add vscode-languageclient@next" + }, + "contributes": { + "configuration": [ + { + "order": 22, + "id": "css", + "title": "%css.title%", + "properties": { + "css.validate": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%css.validate.desc%" + }, + "css.colorDecorators.enable": { + "type": "boolean", + "scope": "window", + "default": true, + "description": "%css.colorDecorators.enable.desc%", + "deprecationMessage": "%css.colorDecorators.enable.deprecationMessage%" + }, + "css.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.compatibleVendorPrefixes.desc%" + }, + "css.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%css.lint.vendorPrefix.desc%" + }, + "css.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.duplicateProperties.desc%" + }, + "css.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%css.lint.emptyRules.desc%" + }, + "css.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.importStatement.desc%" + }, + "css.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.boxModel.desc%" + }, + "css.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.universalSelector.desc%" + }, + "css.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.zeroUnits.desc%" + }, + "css.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%css.lint.fontFaceProperties.desc%" + }, + "css.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "%css.lint.hexColorLength.desc%" + }, + "css.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "%css.lint.argumentsInColorFunction.desc%" + }, + "css.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%css.lint.unknownProperties.desc%" + }, + "css.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.ieHack.desc%" + }, + "css.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.unknownVendorSpecificProperties.desc%" + }, + "css.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%css.lint.propertyIgnoredDueToDisplay.desc%" + }, + "css.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.important.desc%" + }, + "css.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.float.desc%" + }, + "css.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%css.lint.idSelector.desc%" + }, + "css.trace.server": { + "type": "string", + "scope": "window", + "enum": [ + "off", + "messages", + "verbose" + ], + "default": "off", + "description": "%css.trace.server.desc%" + } + } + }, + { + "id": "scss", + "order": 24, + "title": "%scss.title%", + "properties": { + "scss.validate": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%scss.validate.desc%" + }, + "scss.colorDecorators.enable": { + "type": "boolean", + "scope": "window", + "default": true, + "description": "%scss.colorDecorators.enable.desc%", + "deprecationMessage": "%scss.colorDecorators.enable.deprecationMessage%" + }, + "scss.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.compatibleVendorPrefixes.desc%" + }, + "scss.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%scss.lint.vendorPrefix.desc%" + }, + "scss.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.duplicateProperties.desc%" + }, + "scss.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%scss.lint.emptyRules.desc%" + }, + "scss.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.importStatement.desc%" + }, + "scss.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.boxModel.desc%" + }, + "scss.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.universalSelector.desc%" + }, + "scss.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.zeroUnits.desc%" + }, + "scss.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%scss.lint.fontFaceProperties.desc%" + }, + "scss.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "%scss.lint.hexColorLength.desc%" + }, + "scss.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "%scss.lint.argumentsInColorFunction.desc%" + }, + "scss.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%scss.lint.unknownProperties.desc%" + }, + "scss.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.ieHack.desc%" + }, + "scss.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.unknownVendorSpecificProperties.desc%" + }, + "scss.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%scss.lint.propertyIgnoredDueToDisplay.desc%" + }, + "scss.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.important.desc%" + }, + "scss.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.float.desc%" + }, + "scss.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%scss.lint.idSelector.desc%" + } + } + }, + { + "id": "less", + "order": 23, + "type": "object", + "title": "%less.title%", + "properties": { + "less.validate": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%less.validate.desc%" + }, + "less.colorDecorators.enable": { + "type": "boolean", + "scope": "window", + "default": true, + "description": "%less.colorDecorators.enable.desc%", + "deprecationMessage": "%less.colorDecorators.enable.deprecationMessage%" + }, + "less.lint.compatibleVendorPrefixes": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.compatibleVendorPrefixes.desc%" + }, + "less.lint.vendorPrefix": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%less.lint.vendorPrefix.desc%" + }, + "less.lint.duplicateProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.duplicateProperties.desc%" + }, + "less.lint.emptyRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%less.lint.emptyRules.desc%" + }, + "less.lint.importStatement": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.importStatement.desc%" + }, + "less.lint.boxModel": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.boxModel.desc%" + }, + "less.lint.universalSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.universalSelector.desc%" + }, + "less.lint.zeroUnits": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.zeroUnits.desc%" + }, + "less.lint.fontFaceProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%less.lint.fontFaceProperties.desc%" + }, + "less.lint.hexColorLength": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "%less.lint.hexColorLength.desc%" + }, + "less.lint.argumentsInColorFunction": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "error", + "description": "%less.lint.argumentsInColorFunction.desc%" + }, + "less.lint.unknownProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%less.lint.unknownProperties.desc%" + }, + "less.lint.ieHack": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.ieHack.desc%" + }, + "less.lint.unknownVendorSpecificProperties": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.unknownVendorSpecificProperties.desc%" + }, + "less.lint.propertyIgnoredDueToDisplay": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%less.lint.propertyIgnoredDueToDisplay.desc%" + }, + "less.lint.important": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.important.desc%" + }, + "less.lint.float": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.float.desc%" + }, + "less.lint.idSelector": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "ignore", + "description": "%less.lint.idSelector.desc%" + } + } + } + ] + }, + "dependencies": { + "vscode-languageclient": "^4.0.0", + "vscode-languageserver-protocol-foldingprovider": "^1.0.1", + "vscode-nls": "^3.2.1" + }, + "devDependencies": { + "@types/node": "7.0.43" + } +} diff --git a/extensions/css-language-features/package.nls.json b/extensions/css-language-features/package.nls.json new file mode 100644 index 00000000000..cbe77ea0abb --- /dev/null +++ b/extensions/css-language-features/package.nls.json @@ -0,0 +1,74 @@ +{ + "displayName": "CSS Language Features", + "description": "Provides rich language support for CSS, LESS and SCSS files.", + "css.title": "CSS", + "css.lint.argumentsInColorFunction.desc": "Invalid number of parameters", + "css.lint.boxModel.desc": "Do not use width or height when using padding or border", + "css.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties", + "css.lint.duplicateProperties.desc": "Do not use duplicate style definitions", + "css.lint.emptyRules.desc": "Do not use empty rulesets", + "css.lint.float.desc": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.", + "css.lint.fontFaceProperties.desc": "@font-face rule must define 'src' and 'font-family' properties", + "css.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers", + "css.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.", + "css.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older", + "css.lint.important.desc": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.", + "css.lint.importStatement.desc": "Import statements do not load in parallel", + "css.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect", + "css.lint.universalSelector.desc": "The universal selector (*) is known to be slow", + "css.lint.unknownProperties.desc": "Unknown property.", + "css.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", + "css.lint.vendorPrefix.desc": "When using a vendor-specific prefix also include the standard property", + "css.lint.zeroUnits.desc": "No unit for zero needed", + "css.trace.server.desc": "Traces the communication between VS Code and the CSS language server.", + "css.validate.title": "Controls CSS validation and problem severities.", + "css.validate.desc": "Enables or disables all validations", + "less.title": "LESS", + "less.lint.argumentsInColorFunction.desc": "Invalid number of parameters", + "less.lint.boxModel.desc": "Do not use width or height when using padding or border", + "less.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties", + "less.lint.duplicateProperties.desc": "Do not use duplicate style definitions", + "less.lint.emptyRules.desc": "Do not use empty rulesets", + "less.lint.float.desc": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.", + "less.lint.fontFaceProperties.desc": "@font-face rule must define 'src' and 'font-family' properties", + "less.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers", + "less.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.", + "less.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older", + "less.lint.important.desc": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.", + "less.lint.importStatement.desc": "Import statements do not load in parallel", + "less.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect", + "less.lint.universalSelector.desc": "The universal selector (*) is known to be slow", + "less.lint.unknownProperties.desc": "Unknown property.", + "less.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", + "less.lint.vendorPrefix.desc": "When using a vendor-specific prefix also include the standard property", + "less.lint.zeroUnits.desc": "No unit for zero needed", + "less.validate.title": "Controls LESS validation and problem severities.", + "less.validate.desc": "Enables or disables all validations", + "scss.title": "SCSS (Sass)", + "scss.lint.argumentsInColorFunction.desc": "Invalid number of parameters", + "scss.lint.boxModel.desc": "Do not use width or height when using padding or border", + "scss.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties", + "scss.lint.duplicateProperties.desc": "Do not use duplicate style definitions", + "scss.lint.emptyRules.desc": "Do not use empty rulesets", + "scss.lint.float.desc": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.", + "scss.lint.fontFaceProperties.desc": "@font-face rule must define 'src' and 'font-family' properties", + "scss.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers", + "scss.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.", + "scss.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older", + "scss.lint.important.desc": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.", + "scss.lint.importStatement.desc": "Import statements do not load in parallel", + "scss.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect", + "scss.lint.universalSelector.desc": "The universal selector (*) is known to be slow", + "scss.lint.unknownProperties.desc": "Unknown property.", + "scss.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", + "scss.lint.vendorPrefix.desc": "When using a vendor-specific prefix also include the standard property", + "scss.lint.zeroUnits.desc": "No unit for zero needed", + "scss.validate.title": "Controls SCSS validation and problem severities.", + "scss.validate.desc": "Enables or disables all validations", + "less.colorDecorators.enable.desc": "Enables or disables color decorators", + "scss.colorDecorators.enable.desc": "Enables or disables color decorators", + "css.colorDecorators.enable.desc": "Enables or disables color decorators", + "css.colorDecorators.enable.deprecationMessage": "The setting `css.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", + "scss.colorDecorators.enable.deprecationMessage": "The setting `scss.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", + "less.colorDecorators.enable.deprecationMessage": "The setting `less.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`." +} \ No newline at end of file diff --git a/extensions/css/server/.vscode/launch.json b/extensions/css-language-features/server/.vscode/launch.json similarity index 100% rename from extensions/css/server/.vscode/launch.json rename to extensions/css-language-features/server/.vscode/launch.json diff --git a/extensions/css/server/.vscode/tasks.json b/extensions/css-language-features/server/.vscode/tasks.json similarity index 100% rename from extensions/css/server/.vscode/tasks.json rename to extensions/css-language-features/server/.vscode/tasks.json diff --git a/extensions/css/server/package.json b/extensions/css-language-features/server/package.json similarity index 68% rename from extensions/css/server/package.json rename to extensions/css-language-features/server/package.json index 21ec29c7af9..88ed441a3ed 100644 --- a/extensions/css/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -8,17 +8,18 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^3.0.7", - "vscode-emmet-helper": "^1.2.0", - "vscode-languageserver": "4.0.0-next.4" + "vscode-css-languageservice": "^3.0.9-next.3", + "vscode-emmet-helper": "^1.2.4", + "vscode-languageserver": "^4.0.0", + "vscode-languageserver-protocol-foldingprovider": "^1.0.1" }, "devDependencies": { "@types/mocha": "2.2.33", "@types/node": "7.0.43" }, "scripts": { - "compile": "gulp compile-extension:css-server", - "watch": "gulp watch-extension:css-server", + "compile": "gulp compile-extension:css-language-features-server", + "watch": "gulp watch-extension:css-language-features-server", "install-service-next": "yarn add vscode-css-languageservice@next", "install-service-local": "npm install ../../../../vscode-css-languageservice -f", "install-server-next": "yarn add vscode-languageserver@next", diff --git a/extensions/css/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts similarity index 87% rename from extensions/css/server/src/cssServerMain.ts rename to extensions/css-language-features/server/src/cssServerMain.ts index 42cef8ddd33..75223f91b78 100644 --- a/extensions/css/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -5,19 +5,18 @@ 'use strict'; import { - createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities + createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, + ConfigurationRequest, WorkspaceFolder, DocumentColorRequest, ColorPresentationRequest } from 'vscode-languageserver'; -import { TextDocument } from 'vscode-languageserver-types'; - -import { ConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; -import { WorkspaceFolder } from 'vscode-languageserver-protocol/lib/protocol.workspaceFolders.proposed'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { TextDocument, CompletionList } from 'vscode-languageserver-types'; import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; import { formatError, runSafe } from './utils/errors'; -import uri from 'vscode-uri'; +import URI from 'vscode-uri'; +import { getPathCompletionParticipant } from './pathCompletion'; +import { FoldingProviderServerCapabilities, FoldingRangesRequest } from 'vscode-languageserver-protocol-foldingprovider'; export interface Settings { css: LanguageSettings; @@ -60,7 +59,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { if (!Array.isArray(workspaceFolders)) { workspaceFolders = []; if (params.rootPath) { - workspaceFolders.push({ name: '', uri: uri.file(params.rootPath).toString() }); + workspaceFolders.push({ name: '', uri: URI.file(params.rootPath).toString() }); } } @@ -74,7 +73,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { } let snippetSupport = hasClientCapability('textDocument.completion.completionItem.snippetSupport'); scopedSettingsSupport = hasClientCapability('workspace.configuration'); - let capabilities: ServerCapabilities & CPServerCapabilities = { + + let capabilities: ServerCapabilities & FoldingProviderServerCapabilities = { // Tell the client that the server works in FULL text document sync mode textDocumentSync: documents.syncKind, completionProvider: snippetSupport ? { resolveProvider: false } : undefined, @@ -85,7 +85,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { documentHighlightProvider: true, codeActionProvider: true, renameProvider: true, - colorProvider: true + colorProvider: true, + foldingProvider: true }; return { capabilities }; }); @@ -184,7 +185,17 @@ function validateTextDocument(textDocument: TextDocument): void { connection.onCompletion(textDocumentPosition => { return runSafe(() => { let document = documents.get(textDocumentPosition.textDocument.uri); - return getLanguageService(document).doComplete(document, textDocumentPosition.position, stylesheets.get(document))!; /* TODO: remove ! once LS has null annotations */ + const cssLS = getLanguageService(document); + const pathCompletionList: CompletionList = { + isIncomplete: false, + items: [] + }; + cssLS.setCompletionParticipants([getPathCompletionParticipant(document, workspaceFolders, pathCompletionList)]); + const result = cssLS.doComplete(document, textDocumentPosition.position, stylesheets.get(document))!; /* TODO: remove ! once LS has null annotations */ + return { + isIncomplete: result.isIncomplete, + items: [...pathCompletionList.items, ...result.items] + }; }, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`); }); @@ -266,5 +277,13 @@ connection.onRenameRequest(renameParameters => { }, null, `Error while computing renames for ${renameParameters.textDocument.uri}`); }); +connection.onRequest(FoldingRangesRequest.type, (params, token) => { + return runSafe(() => { + let document = documents.get(params.textDocument.uri); + let stylesheet = stylesheets.get(document); + return getLanguageService(document).findFoldingRegions(document, stylesheet); + }, null, `Error while computing folding ranges for ${params.textDocument.uri}`); +}); + // Listen on the connection connection.listen(); \ No newline at end of file diff --git a/extensions/css/server/src/languageModelCache.ts b/extensions/css-language-features/server/src/languageModelCache.ts similarity index 100% rename from extensions/css/server/src/languageModelCache.ts rename to extensions/css-language-features/server/src/languageModelCache.ts diff --git a/extensions/css-language-features/server/src/pathCompletion.ts b/extensions/css-language-features/server/src/pathCompletion.ts new file mode 100644 index 00000000000..76b93f3a628 --- /dev/null +++ b/extensions/css-language-features/server/src/pathCompletion.ts @@ -0,0 +1,119 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as path from 'path'; +import * as fs from 'fs'; +import URI from 'vscode-uri'; + +import { TextDocument, CompletionList, CompletionItemKind, CompletionItem, TextEdit, Range, Position } from 'vscode-languageserver-types'; +import { WorkspaceFolder } from 'vscode-languageserver'; +import { ICompletionParticipant } from 'vscode-css-languageservice'; + +import { startsWith } from './utils/strings'; + +export function getPathCompletionParticipant( + document: TextDocument, + workspaceFolders: WorkspaceFolder[] | undefined, + result: CompletionList +): ICompletionParticipant { + return { + onURILiteralValue: (context: { uriValue: string, position: Position, range: Range; }) => { + if (!workspaceFolders || workspaceFolders.length === 0) { + return; + } + const workspaceRoot = resolveWorkspaceRoot(document, workspaceFolders); + + // Handle quoted values + let uriValue = context.uriValue; + let range = context.range; + if (startsWith(uriValue, `'`) || startsWith(uriValue, `"`)) { + uriValue = uriValue.slice(1, -1); + range = getRangeWithoutQuotes(range); + } + + const suggestions = providePathSuggestions(uriValue, range, URI.parse(document.uri).fsPath, workspaceRoot); + result.items = [...suggestions, ...result.items]; + } + }; +} + +export function providePathSuggestions(value: string, range: Range, activeDocFsPath: string, root?: string): CompletionItem[] { + if (startsWith(value, '/') && !root) { + return []; + } + + let replaceRange: Range; + const lastIndexOfSlash = value.lastIndexOf('/'); + if (lastIndexOfSlash === -1) { + replaceRange = getFullReplaceRange(range); + } else { + const valueAfterLastSlash = value.slice(lastIndexOfSlash + 1); + replaceRange = getReplaceRange(range, valueAfterLastSlash); + } + + let parentDir: string; + if (lastIndexOfSlash === -1) { + parentDir = path.resolve(root); + } else { + const valueBeforeLastSlash = value.slice(0, lastIndexOfSlash + 1); + + parentDir = startsWith(value, '/') + ? path.resolve(root, '.' + valueBeforeLastSlash) + : path.resolve(activeDocFsPath, '..', valueBeforeLastSlash); + } + + try { + return fs.readdirSync(parentDir).map(f => { + if (isDir(path.resolve(parentDir, f))) { + return { + label: f + '/', + kind: CompletionItemKind.Folder, + textEdit: TextEdit.replace(replaceRange, f + '/'), + command: { + title: 'Suggest', + command: 'editor.action.triggerSuggest' + } + }; + } else { + return { + label: f, + kind: CompletionItemKind.File, + textEdit: TextEdit.replace(replaceRange, f) + }; + } + }); + } catch (e) { + return []; + } +} + +const isDir = (p: string) => { + return fs.statSync(p).isDirectory(); +}; + +function resolveWorkspaceRoot(activeDoc: TextDocument, workspaceFolders: WorkspaceFolder[]): string | undefined { + for (let i = 0; i < workspaceFolders.length; i++) { + if (startsWith(activeDoc.uri, workspaceFolders[i].uri)) { + return path.resolve(URI.parse(workspaceFolders[i].uri).fsPath); + } + } +} + +function getFullReplaceRange(valueRange: Range) { + const start = Position.create(valueRange.end.line, valueRange.start.character); + const end = Position.create(valueRange.end.line, valueRange.end.character); + return Range.create(start, end); +} +function getReplaceRange(valueRange: Range, valueAfterLastSlash: string) { + const start = Position.create(valueRange.end.line, valueRange.end.character - valueAfterLastSlash.length); + const end = Position.create(valueRange.end.line, valueRange.end.character); + return Range.create(start, end); +} +function getRangeWithoutQuotes(range: Range) { + const start = Position.create(range.start.line, range.start.character + 1); + const end = Position.create(range.end.line, range.end.character - 1); + return Range.create(start, end); +} diff --git a/extensions/css-language-features/server/src/test/completion.test.ts b/extensions/css-language-features/server/src/test/completion.test.ts new file mode 100644 index 00000000000..518a467cf40 --- /dev/null +++ b/extensions/css-language-features/server/src/test/completion.test.ts @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import 'mocha'; +import * as assert from 'assert'; +import * as path from 'path'; +import Uri from 'vscode-uri'; +import { TextDocument, CompletionList } from 'vscode-languageserver-types'; +import { WorkspaceFolder } from 'vscode-languageserver-protocol'; +import { getPathCompletionParticipant } from '../pathCompletion'; +import { getCSSLanguageService } from 'vscode-css-languageservice'; + +export interface ItemDescription { + label: string; + resultText?: string; +} + +suite('Completions', () => { + const cssLanguageService = getCSSLanguageService(); + + let assertCompletion = function (completions: CompletionList, expected: ItemDescription, document: TextDocument, offset: number) { + let matches = completions.items.filter(completion => { + return completion.label === expected.label; + }); + + assert.equal(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`); + let match = matches[0]; + if (expected.resultText && match.textEdit) { + assert.equal(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText); + } + }; + + function assertCompletions(value: string, expected: { count?: number, items?: ItemDescription[] }, testUri: string, workspaceFolders?: WorkspaceFolder[]): void { + const offset = value.indexOf('|'); + value = value.substr(0, offset) + value.substr(offset + 1); + + const document = TextDocument.create(testUri, 'css', 0, value); + const position = document.positionAt(offset); + + if (!workspaceFolders) { + workspaceFolders = [{ name: 'x', uri: path.dirname(testUri) }]; + } + + let participantResult = CompletionList.create([]); + cssLanguageService.setCompletionParticipants([getPathCompletionParticipant(document, workspaceFolders, participantResult)]); + + const stylesheet = cssLanguageService.parseStylesheet(document); + let list = cssLanguageService.doComplete!(document, position, stylesheet); + list.items = list.items.concat(participantResult.items); + + if (expected.count) { + assert.equal(list.items.length, expected.count); + } + if (expected.items) { + for (let item of expected.items) { + assertCompletion(list, item, document, offset); + } + } + } + + test('CSS Path completion', function () { + let testUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).fsPath; + + assertCompletions('html { background-image: url("./|")', { + items: [ + { label: 'about.html', resultText: 'html { background-image: url("./about.html")' } + ] + }, testUri); + + assertCompletions(`html { background-image: url('../|')`, { + items: [ + { label: 'about/', resultText: `html { background-image: url('../about/')` }, + { label: 'index.html', resultText: `html { background-image: url('../index.html')` }, + { label: 'src/', resultText: `html { background-image: url('../src/')` } + ] + }, testUri); + }); +}); \ No newline at end of file diff --git a/extensions/css/server/src/test/emmet.test.ts b/extensions/css-language-features/server/src/test/emmet.test.ts similarity index 96% rename from extensions/css/server/src/test/emmet.test.ts rename to extensions/css-language-features/server/src/test/emmet.test.ts index 054dc433cc4..7c850fe2697 100644 --- a/extensions/css/server/src/test/emmet.test.ts +++ b/extensions/css-language-features/server/src/test/emmet.test.ts @@ -10,7 +10,7 @@ import { getCSSLanguageService, getSCSSLanguageService } from 'vscode-css-langua import { TextDocument, CompletionList } from 'vscode-languageserver-types'; import { getEmmetCompletionParticipants } from 'vscode-emmet-helper'; -suite('Emmet Support', () => { +suite('CSS Emmet Support', () => { const cssLanguageService = getCSSLanguageService(); const scssLanguageService = getSCSSLanguageService(); @@ -44,6 +44,8 @@ suite('Emmet Support', () => { } test('Css Emmet Completions', function (): any { + this.skip(); // disabled again (see #29113) + assertCompletions('css', '.foo { display: none; m10| }', 'margin: 10px;', 'margin: 10px;'); assertCompletions('css', 'foo { display: none; pos:f| }', 'position: fixed;', 'position: fixed;'); assertCompletions('css', 'foo { display: none; margin: a| }', null, null); @@ -55,6 +57,8 @@ suite('Emmet Support', () => { }); test('Scss Emmet Completions', function (): any { + this.skip(); // disabled again (see #29113) + assertCompletions('scss', '.foo { display: none; .bar { m10| } }', 'margin: 10px;', 'margin: 10px;'); assertCompletions('scss', 'foo { display: none; .bar { pos:f| } }', 'position: fixed;', 'position: fixed;'); assertCompletions('scss', 'foo { display: none; margin: a| .bar {}}', null, null); @@ -64,5 +68,4 @@ suite('Emmet Support', () => { assertCompletions('scss', 'foo { display: none|; }', null, null); assertCompletions('scss', '.foo { display: none; -m-m10| }', 'margin: 10px;', '-moz-margin: 10px;\nmargin: 10px;'); }); - }); \ No newline at end of file diff --git a/extensions/css/server/src/utils/errors.ts b/extensions/css-language-features/server/src/utils/errors.ts similarity index 100% rename from extensions/css/server/src/utils/errors.ts rename to extensions/css-language-features/server/src/utils/errors.ts diff --git a/extensions/css-language-features/server/src/utils/strings.ts b/extensions/css-language-features/server/src/utils/strings.ts new file mode 100644 index 00000000000..f7ad0845cc8 --- /dev/null +++ b/extensions/css-language-features/server/src/utils/strings.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +export function startsWith(haystack: string, needle: string): boolean { + if (haystack.length < needle.length) { + return false; + } + + for (let i = 0; i < needle.length; i++) { + if (haystack[i] !== needle[i]) { + return false; + } + } + + return true; +} diff --git a/extensions/css/server/test/mocha.opts b/extensions/css-language-features/server/test/mocha.opts similarity index 100% rename from extensions/css/server/test/mocha.opts rename to extensions/css-language-features/server/test/mocha.opts diff --git a/extensions/html-language-features/server/test/pathCompletionFixtures/about/about.css b/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.css similarity index 100% rename from extensions/html-language-features/server/test/pathCompletionFixtures/about/about.css rename to extensions/css-language-features/server/test/pathCompletionFixtures/about/about.css diff --git a/extensions/html-language-features/server/test/pathCompletionFixtures/about/about.html b/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.html similarity index 100% rename from extensions/html-language-features/server/test/pathCompletionFixtures/about/about.html rename to extensions/css-language-features/server/test/pathCompletionFixtures/about/about.html diff --git a/extensions/html-language-features/server/test/pathCompletionFixtures/index.html b/extensions/css-language-features/server/test/pathCompletionFixtures/index.html similarity index 100% rename from extensions/html-language-features/server/test/pathCompletionFixtures/index.html rename to extensions/css-language-features/server/test/pathCompletionFixtures/index.html diff --git a/extensions/html-language-features/server/test/pathCompletionFixtures/src/feature.js b/extensions/css-language-features/server/test/pathCompletionFixtures/src/feature.js similarity index 100% rename from extensions/html-language-features/server/test/pathCompletionFixtures/src/feature.js rename to extensions/css-language-features/server/test/pathCompletionFixtures/src/feature.js diff --git a/extensions/html-language-features/server/test/pathCompletionFixtures/src/test.js b/extensions/css-language-features/server/test/pathCompletionFixtures/src/test.js similarity index 100% rename from extensions/html-language-features/server/test/pathCompletionFixtures/src/test.js rename to extensions/css-language-features/server/test/pathCompletionFixtures/src/test.js diff --git a/extensions/css/server/tsconfig.json b/extensions/css-language-features/server/tsconfig.json similarity index 100% rename from extensions/css/server/tsconfig.json rename to extensions/css-language-features/server/tsconfig.json diff --git a/extensions/css/server/yarn.lock b/extensions/css-language-features/server/yarn.lock similarity index 53% rename from extensions/css/server/yarn.lock rename to extensions/css-language-features/server/yarn.lock index 0c0ace42012..8ce04e915c9 100644 --- a/extensions/css/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -18,46 +18,57 @@ jsonc-parser@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-1.0.0.tgz#ddcc864ae708e60a7a6dd36daea00172fa8d9272" -vscode-css-languageservice@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.7.tgz#ca53f94db020e4e6c7059963fed8dc256593decc" +vscode-css-languageservice@^3.0.9-next.3: + version "3.0.9-next.3" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.9-next.3.tgz#c6b8baf316d3b87d5896d2694721d6b90ce41c00" dependencies: - vscode-languageserver-types "^3.6.0-next.1" - vscode-nls "^2.0.1" + vscode-languageserver-types "^3.6.1" + vscode-nls "^3.2.1" -vscode-emmet-helper@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.0.tgz#6b9311be065c9c99d5de2dae18ea0730d9cfb734" +vscode-emmet-helper@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.4.tgz#48056974d13036722af019235b9f750a495de728" dependencies: "@emmetio/extract-abbreviation" "0.1.6" jsonc-parser "^1.0.0" vscode-languageserver-types "^3.6.0-next.1" -vscode-jsonrpc@^3.6.0-next.1: - version "3.6.0-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0-next.1.tgz#3cb463dffe5842d6aec16718ca9252708cd6aabe" +vscode-jsonrpc@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0.tgz#848d56995d5168950d84feb5d9c237ae5c6a02d4" -vscode-languageserver-protocol@^3.6.0-next.5: - version "3.6.0-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0-next.5.tgz#ed2ec2db759826f753c0a13977dfb2bedc4d31b3" +vscode-languageserver-protocol-foldingprovider@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol-foldingprovider/-/vscode-languageserver-protocol-foldingprovider-1.0.1.tgz#85514aaf8fe905e91bf21e4106e0847f60d40f44" dependencies: - vscode-jsonrpc "^3.6.0-next.1" - vscode-languageserver-types "^3.6.0-next.1" + vscode-languageserver-protocol "^3.6.0" + vscode-languageserver-types "^3.6.0" + +vscode-languageserver-protocol@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0.tgz#579642cdcccf74b0cd771c33daa3239acb40d040" + dependencies: + vscode-jsonrpc "^3.6.0" + vscode-languageserver-types "^3.6.0" + +vscode-languageserver-types@^3.6.0, vscode-languageserver-types@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.1.tgz#4bc06a48dff653495f12f94b8b1e228988a1748d" vscode-languageserver-types@^3.6.0-next.1: version "3.6.0-next.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3" -vscode-languageserver@4.0.0-next.4: - version "4.0.0-next.4" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.0.0-next.4.tgz#162440b15bedaab07e1676f046e4d9b8578b3d92" +vscode-languageserver@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.0.0.tgz#8b792f0d6d10acfe363d02371ed4ce53d08af88a" dependencies: - vscode-languageserver-protocol "^3.6.0-next.5" + vscode-languageserver-protocol "^3.6.0" vscode-uri "^1.0.1" -vscode-nls@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350" vscode-uri@^1.0.1: version "1.0.1" diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock new file mode 100644 index 00000000000..7b01c6fe5ce --- /dev/null +++ b/extensions/css-language-features/yarn.lock @@ -0,0 +1,39 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@7.0.43": + version "7.0.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" + +vscode-jsonrpc@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0.tgz#848d56995d5168950d84feb5d9c237ae5c6a02d4" + +vscode-languageclient@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-4.0.0.tgz#635f5bfbcfa1385dae489b394857f1db8b459a7d" + dependencies: + vscode-languageserver-protocol "^3.6.0" + +vscode-languageserver-protocol-foldingprovider@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol-foldingprovider/-/vscode-languageserver-protocol-foldingprovider-1.0.1.tgz#85514aaf8fe905e91bf21e4106e0847f60d40f44" + dependencies: + vscode-languageserver-protocol "^3.6.0" + vscode-languageserver-types "^3.6.0" + +vscode-languageserver-protocol@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0.tgz#579642cdcccf74b0cd771c33daa3239acb40d040" + dependencies: + vscode-jsonrpc "^3.6.0" + vscode-languageserver-types "^3.6.0" + +vscode-languageserver-types@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.1.tgz#4bc06a48dff653495f12f94b8b1e228988a1748d" + +vscode-nls@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51" diff --git a/extensions/css/.vscodeignore b/extensions/css/.vscodeignore index 7b2f560d103..77ab386fc7d 100644 --- a/extensions/css/.vscodeignore +++ b/extensions/css/.vscodeignore @@ -1,6 +1 @@ -test/** -client/src/** -client/tsconfig.json -server/src/** -server/tsconfig.json -server/node_modules/@types/** \ No newline at end of file +test/** \ No newline at end of file diff --git a/extensions/css/OSSREADME.json b/extensions/css/OSSREADME.json index a5bb212fc77..fce1575aed7 100644 --- a/extensions/css/OSSREADME.json +++ b/extensions/css/OSSREADME.json @@ -5,5 +5,4 @@ "license": "MIT", "repositoryURL": "https://github.com/atom/language-css", "description": "The file syntaxes/css.tmLanguage.json was derived from the Atom package https://github.com/atom/language-css which was originally converted from the TextMate bundle https://github.com/textmate/css.tmbundle." - }] diff --git a/extensions/css/package.json b/extensions/css/package.json index c68bf31d5c2..9517029a69f 100644 --- a/extensions/css/package.json +++ b/extensions/css/package.json @@ -7,19 +7,7 @@ "engines": { "vscode": "0.10.x" }, - "icon": "icons/css.png", - "activationEvents": [ - "onLanguage:css", - "onLanguage:less", - "onLanguage:scss", - "onCommand:_css.applyCodeAction" - ], - "enableProposedApi": true, - "main": "./client/out/cssMain", "scripts": { - "compile": "gulp compile-extension:css-client && gulp compile-extension:css-server", - "postinstall": "cd server && yarn install", - "install-client-next": "yarn add vscode-languageclient@next", "update-grammar": "node ../../build/npm/update-grammar.js atom/language-css grammars/css.cson ./syntaxes/css.tmLanguage.json" }, "contributes": { @@ -43,683 +31,11 @@ { "language": "css", "scopeName": "source.css", - "path": "./syntaxes/css.tmLanguage.json" - } - ], - "configuration": [ - { - "order": 22, - "id": "css", - "title": "%css.title%", - "properties": { - "css.validate": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "%css.validate.desc%" - }, - "css.colorDecorators.enable": { - "type": "boolean", - "scope": "window", - "default": true, - "description": "%css.colorDecorators.enable.desc%", - "deprecationMessage": "%css.colorDecorators.enable.deprecationMessage%" - }, - "css.lint.compatibleVendorPrefixes": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.compatibleVendorPrefixes.desc%" - }, - "css.lint.vendorPrefix": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%css.lint.vendorPrefix.desc%" - }, - "css.lint.duplicateProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.duplicateProperties.desc%" - }, - "css.lint.emptyRules": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%css.lint.emptyRules.desc%" - }, - "css.lint.importStatement": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.importStatement.desc%" - }, - "css.lint.boxModel": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.boxModel.desc%" - }, - "css.lint.universalSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.universalSelector.desc%" - }, - "css.lint.zeroUnits": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.zeroUnits.desc%" - }, - "css.lint.fontFaceProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%css.lint.fontFaceProperties.desc%" - }, - "css.lint.hexColorLength": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "%css.lint.hexColorLength.desc%" - }, - "css.lint.argumentsInColorFunction": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "%css.lint.argumentsInColorFunction.desc%" - }, - "css.lint.unknownProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%css.lint.unknownProperties.desc%" - }, - "css.lint.ieHack": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.ieHack.desc%" - }, - "css.lint.unknownVendorSpecificProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.unknownVendorSpecificProperties.desc%" - }, - "css.lint.propertyIgnoredDueToDisplay": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%css.lint.propertyIgnoredDueToDisplay.desc%" - }, - "css.lint.important": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.important.desc%" - }, - "css.lint.float": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.float.desc%" - }, - "css.lint.idSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%css.lint.idSelector.desc%" - }, - "css.trace.server": { - "type": "string", - "scope": "window", - "enum": [ - "off", - "messages", - "verbose" - ], - "default": "off", - "description": "%css.trace.server.desc%" - } - } - }, - { - "id": "scss", - "order": 24, - "title": "%scss.title%", - "properties": { - "scss.validate": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "%scss.validate.desc%" - }, - "scss.colorDecorators.enable": { - "type": "boolean", - "scope": "window", - "default": true, - "description": "%scss.colorDecorators.enable.desc%", - "deprecationMessage": "%scss.colorDecorators.enable.deprecationMessage%" - }, - "scss.lint.compatibleVendorPrefixes": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.compatibleVendorPrefixes.desc%" - }, - "scss.lint.vendorPrefix": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%scss.lint.vendorPrefix.desc%" - }, - "scss.lint.duplicateProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.duplicateProperties.desc%" - }, - "scss.lint.emptyRules": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%scss.lint.emptyRules.desc%" - }, - "scss.lint.importStatement": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.importStatement.desc%" - }, - "scss.lint.boxModel": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.boxModel.desc%" - }, - "scss.lint.universalSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.universalSelector.desc%" - }, - "scss.lint.zeroUnits": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.zeroUnits.desc%" - }, - "scss.lint.fontFaceProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%scss.lint.fontFaceProperties.desc%" - }, - "scss.lint.hexColorLength": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "%scss.lint.hexColorLength.desc%" - }, - "scss.lint.argumentsInColorFunction": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "%scss.lint.argumentsInColorFunction.desc%" - }, - "scss.lint.unknownProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%scss.lint.unknownProperties.desc%" - }, - "scss.lint.ieHack": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.ieHack.desc%" - }, - "scss.lint.unknownVendorSpecificProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.unknownVendorSpecificProperties.desc%" - }, - "scss.lint.propertyIgnoredDueToDisplay": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%scss.lint.propertyIgnoredDueToDisplay.desc%" - }, - "scss.lint.important": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.important.desc%" - }, - "scss.lint.float": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.float.desc%" - }, - "scss.lint.idSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%scss.lint.idSelector.desc%" - } - } - }, - { - "id": "less", - "order": 23, - "type": "object", - "title": "%less.title%", - "properties": { - "less.validate": { - "type": "boolean", - "scope": "resource", - "default": true, - "description": "%less.validate.desc%" - }, - "less.colorDecorators.enable": { - "type": "boolean", - "scope": "window", - "default": true, - "description": "%less.colorDecorators.enable.desc%", - "deprecationMessage": "%less.colorDecorators.enable.deprecationMessage%" - }, - "less.lint.compatibleVendorPrefixes": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.compatibleVendorPrefixes.desc%" - }, - "less.lint.vendorPrefix": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%less.lint.vendorPrefix.desc%" - }, - "less.lint.duplicateProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.duplicateProperties.desc%" - }, - "less.lint.emptyRules": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%less.lint.emptyRules.desc%" - }, - "less.lint.importStatement": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.importStatement.desc%" - }, - "less.lint.boxModel": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.boxModel.desc%" - }, - "less.lint.universalSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.universalSelector.desc%" - }, - "less.lint.zeroUnits": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.zeroUnits.desc%" - }, - "less.lint.fontFaceProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%less.lint.fontFaceProperties.desc%" - }, - "less.lint.hexColorLength": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "%less.lint.hexColorLength.desc%" - }, - "less.lint.argumentsInColorFunction": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "error", - "description": "%less.lint.argumentsInColorFunction.desc%" - }, - "less.lint.unknownProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%less.lint.unknownProperties.desc%" - }, - "less.lint.ieHack": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.ieHack.desc%" - }, - "less.lint.unknownVendorSpecificProperties": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.unknownVendorSpecificProperties.desc%" - }, - "less.lint.propertyIgnoredDueToDisplay": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "warning", - "description": "%less.lint.propertyIgnoredDueToDisplay.desc%" - }, - "less.lint.important": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.important.desc%" - }, - "less.lint.float": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.float.desc%" - }, - "less.lint.idSelector": { - "type": "string", - "scope": "resource", - "enum": [ - "ignore", - "warning", - "error" - ], - "default": "ignore", - "description": "%less.lint.idSelector.desc%" - } + "path": "./syntaxes/css.tmLanguage.json", + "tokenTypes": { + "meta.function.url string.quoted": "other" } } ] - }, - "dependencies": { - "vscode-languageclient": "4.0.0-next.9", - "vscode-nls": "^3.2.1" - }, - "devDependencies": { - "@types/node": "7.0.43" } } diff --git a/extensions/css/package.nls.json b/extensions/css/package.nls.json index cbe77ea0abb..b4ff0da7673 100644 --- a/extensions/css/package.nls.json +++ b/extensions/css/package.nls.json @@ -1,74 +1,4 @@ { - "displayName": "CSS Language Features", - "description": "Provides rich language support for CSS, LESS and SCSS files.", - "css.title": "CSS", - "css.lint.argumentsInColorFunction.desc": "Invalid number of parameters", - "css.lint.boxModel.desc": "Do not use width or height when using padding or border", - "css.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties", - "css.lint.duplicateProperties.desc": "Do not use duplicate style definitions", - "css.lint.emptyRules.desc": "Do not use empty rulesets", - "css.lint.float.desc": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.", - "css.lint.fontFaceProperties.desc": "@font-face rule must define 'src' and 'font-family' properties", - "css.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers", - "css.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.", - "css.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older", - "css.lint.important.desc": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.", - "css.lint.importStatement.desc": "Import statements do not load in parallel", - "css.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect", - "css.lint.universalSelector.desc": "The universal selector (*) is known to be slow", - "css.lint.unknownProperties.desc": "Unknown property.", - "css.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", - "css.lint.vendorPrefix.desc": "When using a vendor-specific prefix also include the standard property", - "css.lint.zeroUnits.desc": "No unit for zero needed", - "css.trace.server.desc": "Traces the communication between VS Code and the CSS language server.", - "css.validate.title": "Controls CSS validation and problem severities.", - "css.validate.desc": "Enables or disables all validations", - "less.title": "LESS", - "less.lint.argumentsInColorFunction.desc": "Invalid number of parameters", - "less.lint.boxModel.desc": "Do not use width or height when using padding or border", - "less.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties", - "less.lint.duplicateProperties.desc": "Do not use duplicate style definitions", - "less.lint.emptyRules.desc": "Do not use empty rulesets", - "less.lint.float.desc": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.", - "less.lint.fontFaceProperties.desc": "@font-face rule must define 'src' and 'font-family' properties", - "less.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers", - "less.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.", - "less.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older", - "less.lint.important.desc": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.", - "less.lint.importStatement.desc": "Import statements do not load in parallel", - "less.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect", - "less.lint.universalSelector.desc": "The universal selector (*) is known to be slow", - "less.lint.unknownProperties.desc": "Unknown property.", - "less.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", - "less.lint.vendorPrefix.desc": "When using a vendor-specific prefix also include the standard property", - "less.lint.zeroUnits.desc": "No unit for zero needed", - "less.validate.title": "Controls LESS validation and problem severities.", - "less.validate.desc": "Enables or disables all validations", - "scss.title": "SCSS (Sass)", - "scss.lint.argumentsInColorFunction.desc": "Invalid number of parameters", - "scss.lint.boxModel.desc": "Do not use width or height when using padding or border", - "scss.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties", - "scss.lint.duplicateProperties.desc": "Do not use duplicate style definitions", - "scss.lint.emptyRules.desc": "Do not use empty rulesets", - "scss.lint.float.desc": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.", - "scss.lint.fontFaceProperties.desc": "@font-face rule must define 'src' and 'font-family' properties", - "scss.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers", - "scss.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.", - "scss.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older", - "scss.lint.important.desc": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.", - "scss.lint.importStatement.desc": "Import statements do not load in parallel", - "scss.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect", - "scss.lint.universalSelector.desc": "The universal selector (*) is known to be slow", - "scss.lint.unknownProperties.desc": "Unknown property.", - "scss.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", - "scss.lint.vendorPrefix.desc": "When using a vendor-specific prefix also include the standard property", - "scss.lint.zeroUnits.desc": "No unit for zero needed", - "scss.validate.title": "Controls SCSS validation and problem severities.", - "scss.validate.desc": "Enables or disables all validations", - "less.colorDecorators.enable.desc": "Enables or disables color decorators", - "scss.colorDecorators.enable.desc": "Enables or disables color decorators", - "css.colorDecorators.enable.desc": "Enables or disables color decorators", - "css.colorDecorators.enable.deprecationMessage": "The setting `css.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", - "scss.colorDecorators.enable.deprecationMessage": "The setting `scss.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", - "less.colorDecorators.enable.deprecationMessage": "The setting `less.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`." + "displayName": "CSS Language Basics", + "description": "Provides syntax highlighting and bracket matching for CSS, LESS and SCSS files." } \ No newline at end of file diff --git a/extensions/css/yarn.lock b/extensions/css/yarn.lock deleted file mode 100644 index 5f63bd90373..00000000000 --- a/extensions/css/yarn.lock +++ /dev/null @@ -1,32 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@7.0.43": - version "7.0.43" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" - -vscode-jsonrpc@^3.6.0-next.1: - version "3.6.0-next.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0-next.1.tgz#3cb463dffe5842d6aec16718ca9252708cd6aabe" - -vscode-languageclient@4.0.0-next.9: - version "4.0.0-next.9" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-4.0.0-next.9.tgz#2a06568f46ee9de3490f85e227d3740a21a03d3a" - dependencies: - vscode-languageserver-protocol "^3.6.0-next.5" - -vscode-languageserver-protocol@^3.6.0-next.5: - version "3.6.0-next.5" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0-next.5.tgz#ed2ec2db759826f753c0a13977dfb2bedc4d31b3" - dependencies: - vscode-jsonrpc "^3.6.0-next.1" - vscode-languageserver-types "^3.6.0-next.1" - -vscode-languageserver-types@^3.6.0-next.1: - version "3.6.0-next.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3" - -vscode-nls@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51" diff --git a/extensions/docker/OSSREADME.json b/extensions/docker/OSSREADME.json index 28c0191ec17..bc514d5d8b4 100644 --- a/extensions/docker/OSSREADME.json +++ b/extensions/docker/OSSREADME.json @@ -4,5 +4,5 @@ "version": "0.0.0", "license": "Apache2", "repositoryURL": "https://github.com/moby/moby", - "description": "The file syntaxes/Dockerfile.tmLanguage was included from https://github.com/moby/moby/blob/master/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage." + "description": "The file syntaxes/docker.tmLanguage was included from https://github.com/moby/moby/blob/master/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage." }] diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 7bf52dce604..26c3a58b43a 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -439,7 +439,7 @@ "@emmetio/html-matcher": "^0.3.3", "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", "@emmetio/math-expression": "^0.1.1", - "vscode-emmet-helper": "^1.2.2", + "vscode-emmet-helper": "^1.2.4", "vscode-languageserver-types": "^3.5.0", "image-size": "^0.5.2", "vscode-nls": "3.2.1" diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 9441ccdebde..9e50cc06cde 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Node, HtmlNode, Rule, Property } from 'EmmetNode'; -import { getEmmetHelper, getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, validate, getEmmetConfiguration, isStyleSheet, getEmmetMode } from './util'; +import { Node, HtmlNode, Rule, Property, Stylesheet } from 'EmmetNode'; +import { getEmmetHelper, getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, validate, getEmmetConfiguration, isStyleSheet, getEmmetMode, parsePartialStylesheet } from './util'; const trimRegex = /[\u00a0]*[\d|#|\-|\*|\u2022]+\.?/; const hexColorRegex = /^#\d+$/; @@ -227,8 +227,12 @@ export function expandEmmetAbbreviation(args: any): Thenable 1000) { + rootNode = parsePartialStylesheet(editor.document, editor.selection.isReversed ? editor.selection.anchor : editor.selection.active); + } else { + rootNode = parseDocument(editor.document, false); + } // When tabbed on a non empty selection, do not treat it as an emmet abbreviation, and fallback to tab instead if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) { @@ -290,8 +294,7 @@ export function expandEmmetAbbreviation(args: any): Thenable { * Checks if given position is a valid location to expand emmet abbreviation. * Works only on html and css/less/scss syntax * @param document current Text Document - * @param currentNode parsed node at given position + * @param rootNode parsed document * @param syntax syntax of the abbreviation * @param position position to validate * @param abbreviationRange The range of the abbreviation for which given position is being validated */ -export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocument, currentNode: Node | null, syntax: string, position: vscode.Position, abbreviationRange: vscode.Range): boolean { +export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocument, rootNode: Node | undefined, syntax: string, position: vscode.Position, abbreviationRange: vscode.Range): boolean { + const currentNode = rootNode ? getNode(rootNode, position, true) : null; if (isStyleSheet(syntax)) { + const stylesheet = rootNode; + if (stylesheet && (stylesheet.comments || []).some(x => position.isAfterOrEqual(x.start) && position.isBeforeOrEqual(x.end))) { + return false; + } // Continue validation only if the file was parse-able and the currentNode has been found if (!currentNode) { return true; diff --git a/extensions/emmet/src/bufferStream.ts b/extensions/emmet/src/bufferStream.ts index 152724c2039..6f71b0909c1 100644 --- a/extensions/emmet/src/bufferStream.ts +++ b/extensions/emmet/src/bufferStream.ts @@ -17,6 +17,7 @@ export class DocumentStreamReader { private document: TextDocument; private start: Position; private _eof: Position; + private _sof: Position; public pos: Position; private _eol: string; @@ -24,10 +25,18 @@ export class DocumentStreamReader { this.document = document; this.start = this.pos = pos ? pos : new Position(0, 0); + this._sof = limit ? limit.start : new Position(0, 0); this._eof = limit ? limit.end : new Position(this.document.lineCount - 1, this._lineLength(this.document.lineCount - 1)); this._eol = this.document.eol === EndOfLine.LF ? '\n' : '\r\n'; } + /** + * Returns true only if the stream is at the start of the file. + */ + sof(): boolean { + return this.pos.isBeforeOrEqual(this._sof); + } + /** * Returns true only if the stream is at the end of the file. */ diff --git a/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts index 0daed26f446..962171ba6b1 100644 --- a/extensions/emmet/src/defaultCompletionProvider.ts +++ b/extensions/emmet/src/defaultCompletionProvider.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Node } from 'EmmetNode'; +import { Stylesheet } from 'EmmetNode'; import { isValidLocationForEmmetAbbreviation } from './abbreviationActions'; -import { getEmmetHelper, getNode, getMappingForIncludedLanguages, parseDocument, getEmmetConfiguration, getEmmetMode, isStyleSheet } from './util'; +import { getEmmetHelper, getMappingForIncludedLanguages, parsePartialStylesheet, getEmmetConfiguration, getEmmetMode, isStyleSheet, parseDocument, } from './util'; export class DefaultCompletionItemProvider implements vscode.CompletionItemProvider { - public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable | undefined { + public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Thenable | undefined { const emmetConfig = vscode.workspace.getConfiguration('emmet'); const excludedLanguages = emmetConfig['excludeLanguages'] ? emmetConfig['excludeLanguages'] : []; if (excludedLanguages.indexOf(document.languageId) > -1) { @@ -28,26 +28,26 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi } const helper = getEmmetHelper(); - const extractAbbreviationResults = helper.extractAbbreviation(document, position); - if (!extractAbbreviationResults) { + const extractAbbreviationResults = helper.extractAbbreviation(document, position, !isStyleSheet(syntax)); + if (!extractAbbreviationResults || !helper.isAbbreviationValid(syntax, extractAbbreviationResults.abbreviation)) { return; } - let validateLocation = syntax === 'html'; - let currentNode: Node | null = null; + let validateLocation = false; + let rootNode: Stylesheet | undefined = undefined; - // If document can be css parsed, get currentNode - if (isStyleSheet(document.languageId)) { - const rootNode = parseDocument(document, false); - if (!rootNode) { - return; + if (context.triggerKind !== vscode.CompletionTriggerKind.TriggerForIncompleteCompletions) { + validateLocation = syntax === 'html' || isStyleSheet(document.languageId); + // If document can be css parsed, get currentNode + if (isStyleSheet(document.languageId)) { + rootNode = document.lineCount > 1000 ? parsePartialStylesheet(document, position) : parseDocument(document, false); + if (!rootNode) { + return; + } } - - currentNode = getNode(rootNode, position, true); - validateLocation = true; } - if (validateLocation && !isValidLocationForEmmetAbbreviation(document, currentNode, syntax, position, extractAbbreviationResults.abbreviationRange)) { + if (validateLocation && !isValidLocationForEmmetAbbreviation(document, rootNode, syntax, position, extractAbbreviationResults.abbreviationRange)) { return; } @@ -96,10 +96,4 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return new vscode.CompletionList(newItems, true); }); } - - - - - - } \ No newline at end of file diff --git a/extensions/emmet/src/splitJoinTag.ts b/extensions/emmet/src/splitJoinTag.ts index 67a403bce29..38d2b163c01 100644 --- a/extensions/emmet/src/splitJoinTag.ts +++ b/extensions/emmet/src/splitJoinTag.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import { HtmlNode } from 'EmmetNode'; -import { getNode, parseDocument, validate } from './util'; +import { getNode, parseDocument, validate, getEmmetMode, getEmmetConfiguration } from './util'; export function splitJoinTag() { if (!validate(false) || !vscode.window.activeTextEditor) { @@ -48,6 +48,14 @@ function getRangesToReplace(document: vscode.TextDocument, nodeToUpdate: HtmlNod let end = nodeToUpdate.end; rangeToReplace = new vscode.Range(start, end); textToReplaceWith = '/>'; + + const emmetMode = getEmmetMode(document.languageId, []) || ''; + const emmetConfig = getEmmetConfiguration(emmetMode); + if (emmetMode && emmetConfig.syntaxProfiles[emmetMode] && + (emmetConfig.syntaxProfiles[emmetMode]['selfClosingStyle'] === 'xhtml' || emmetConfig.syntaxProfiles[emmetMode]['self_closing_tag'] === 'xhtml')) { + textToReplaceWith = ' ' + textToReplaceWith; + } + } return new vscode.TextEdit(rangeToReplace, textToReplaceWith); diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index 4f914717061..cf4ba401a23 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { Selection, workspace, CompletionList, CancellationTokenSource } from 'vscode'; +import { Selection, workspace, CompletionList, CancellationTokenSource, CompletionTriggerKind } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { expandEmmetAbbreviation } from '../abbreviationActions'; import { DefaultCompletionItemProvider } from '../defaultCompletionProvider'; @@ -63,7 +63,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor('img', 'html', (editor, doc) => { editor.selection = new Selection(0, 3, 0, 3); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { assert.equal(!completionPromise, false, `Got unexpected undefined instead of a completion promise`); return Promise.resolve(); @@ -165,7 +165,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { editor.selection = new Selection(2, 4, 2, 4); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); return Promise.resolve(); }); @@ -185,7 +185,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { editor.selection = new Selection(9, 8, 9, 8); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); return Promise.resolve(); }); @@ -207,7 +207,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor(fileContents, 'html', (editor, doc) => { editor.selection = new Selection(0, 6, 0, 6); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); return Promise.resolve(); }); @@ -234,7 +234,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { // return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { // editor.selection = new Selection(13, 3, 13, 6); // const cancelSrc = new CancellationTokenSource(); - // const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + // const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); // if (!completionPromise) { // assert.equal(1, 2, `Problem with expanding m10`); // return Promise.resolve(); @@ -347,7 +347,7 @@ function testHtmlCompletionProvider(selection: Selection, abbreviation: string, return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { editor.selection = selection; const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { if (!shouldFail) { assert.equal(1, 2, `Problem with expanding ${abbreviation} to ${expandedText}`); diff --git a/extensions/emmet/src/test/cssAbbreviationAction.test.ts b/extensions/emmet/src/test/cssAbbreviationAction.test.ts index 4f07358638b..78dd6c7c3ba 100644 --- a/extensions/emmet/src/test/cssAbbreviationAction.test.ts +++ b/extensions/emmet/src/test/cssAbbreviationAction.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { Selection, CompletionList, CancellationTokenSource, Position } from 'vscode'; +import { Selection, CompletionList, CancellationTokenSource, Position, CompletionTriggerKind } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { expandEmmetAbbreviation } from '../abbreviationActions'; import { DefaultCompletionItemProvider } from '../defaultCompletionProvider'; @@ -65,6 +65,30 @@ suite('Tests for Expand Abbreviations (CSS)', () => { }); }); + test('No emmet when cursor inside comment (CSS)', () => { + const testContent = ` +.foo { + /*margin: 10px; + m10 + padding: 10px;*/ + display: auto; +} +`; + + return withRandomFileEditor(testContent, 'css', (editor, doc) => { + editor.selection = new Selection(3, 4, 3, 4); + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), testContent); + const cancelSrc = new CancellationTokenSource(); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + if (completionPromise) { + assert.equal(1, 2, `Invalid completion at property value`); + } + return Promise.resolve(); + }); + }); + }); + test('No emmet when cursor in selector of a rule (CSS)', () => { const testContent = ` .foo { @@ -79,7 +103,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } @@ -101,7 +125,24 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + if (completionPromise) { + assert.equal(1, 2, `Invalid completion at property value`); + } + return Promise.resolve(); + }); + }); + }); + + test('Skip when typing the last property value in single line rules (CSS)', () => { + const testContent = `.foo {padding: 10px; margin: a}`; + + return withRandomFileEditor(testContent, 'css', (editor, doc) => { + editor.selection = new Selection(0, 30, 0, 30); + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), testContent); + const cancelSrc = new CancellationTokenSource(); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(0, 30), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } @@ -123,7 +164,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent.replace('#12', '#121212')); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { assert.fail('Completion promise wasnt returned'); return Promise.resolve(); @@ -153,7 +194,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } @@ -175,7 +216,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent.replace('#12', '#121212')); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 12), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { assert.fail('Completion promise wasnt returned'); return Promise.resolve(); @@ -204,7 +245,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } @@ -225,7 +266,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent.replace('#12', '#121212')); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { assert.fail('Completion promise wasnt returned'); return Promise.resolve(); @@ -249,8 +290,8 @@ nav# return withRandomFileEditor(cssContents, 'css', (editor, doc) => { editor.selection = new Selection(3, 1, 3, 6); const cancelSrc = new CancellationTokenSource(); - const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 6), cancelSrc.token); - const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 6), cancelSrc.token); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 6), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 6), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise1 || !completionPromise2) { assert.equal(1, 2, `Problem with expanding pos:f`); return Promise.resolve(); @@ -295,10 +336,10 @@ nav# return withRandomFileEditor(scssContents, 'scss', (editor, doc) => { editor.selection = new Selection(3, 4, 3, 4); const cancelSrc = new CancellationTokenSource(); - const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 4), cancelSrc.token); - const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 5), cancelSrc.token); - const completionPromise3 = completionProvider.provideCompletionItems(editor.document, new Position(11, 4), cancelSrc.token); - const completionPromise4 = completionProvider.provideCompletionItems(editor.document, new Position(14, 5), cancelSrc.token); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 4), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 5), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise3 = completionProvider.provideCompletionItems(editor.document, new Position(11, 4), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise4 = completionProvider.provideCompletionItems(editor.document, new Position(14, 5), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise1) { assert.equal(1, 2, `Problem with expanding padding abbreviations at line 3 col 4`); } @@ -375,13 +416,13 @@ m10 return withRandomFileEditor(scssContentsNoExpand, 'scss', (editor, doc) => { editor.selection = new Selection(1, 3, 1, 3); // outside rule const cancelSrc = new CancellationTokenSource(); - let completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + let completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `m10 gets expanded in invalid location (outside rule)`); } editor.selection = new Selection(5, 15, 5, 15); // in the value part of property value - completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { return completionPromise.then((completionList: CompletionList) => { if (completionList && completionList.items && completionList.items.length > 0) { @@ -402,7 +443,7 @@ m10 return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), scssContents); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(19, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(19, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } diff --git a/extensions/emmet/src/test/tagActions.test.ts b/extensions/emmet/src/test/tagActions.test.ts index fa4f680cd18..db664524eb1 100644 --- a/extensions/emmet/src/test/tagActions.test.ts +++ b/extensions/emmet/src/test/tagActions.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { Selection } from 'vscode'; +import { Selection, workspace } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { removeTag } from '../removeTag'; import { updateTag } from '../updateTag'; @@ -14,7 +14,10 @@ import { splitJoinTag } from '../splitJoinTag'; import { mergeLines } from '../mergeLines'; suite('Tests for Emmet actions on html tags', () => { - teardown(closeAllEditors); + teardown(() => { + // Reset config and close all editors + return workspace.getConfiguration('emmet').update('syntaxProfiles', {}).then(closeAllEditors); + }); const contents = `
@@ -102,6 +105,32 @@ suite('Tests for Emmet actions on html tags', () => { }); }); + test('split/join tag in jsx with xhtml self closing tag', () => { + const expectedContents = ` +
+
    +
  • +
  • There
  • +
  • Bye
  • +
+ +
+ `; + return workspace.getConfiguration('emmet').update('syntaxProfiles', {jsx: {selfClosingStyle: 'xhtml'}}).then(() =>{ + return withRandomFileEditor(contents, 'jsx', (editor, doc) => { + editor.selections = [ + new Selection(3, 17, 3, 17), // join tag + new Selection(7, 5, 7, 5), // split tag + ]; + + return splitJoinTag()!.then(() => { + assert.equal(doc.getText(), expectedContents); + return Promise.resolve() + }); + }); + }); + }); + test('match tag with mutliple cursors', () => { return withRandomFileEditor(contents, 'html', (editor, doc) => { editor.selections = [ diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index e9f21c463ae..0fb4471eda5 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import parse from '@emmetio/html-matcher'; import parseStylesheet from '@emmetio/css-parser'; -import { Node, HtmlNode, CssToken, Property, Rule } from 'EmmetNode'; +import { Node, HtmlNode, CssToken, Property, Rule, Stylesheet } from 'EmmetNode'; import { DocumentStreamReader } from './bufferStream'; let _emmetHelper: any; @@ -128,6 +128,155 @@ export function parseDocument(document: vscode.TextDocument, showError: boolean return undefined; } +export function parsePartialStylesheet(document: vscode.TextDocument, position: vscode.Position): Stylesheet | undefined { + + let startPosition = new vscode.Position(0, 0); + let endPosition = new vscode.Position(document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length); + const closeBrace = 125; + const openBrace = 123; + let slash = 47; + let star = 42; + let isCSS = document.languageId === 'css'; + + let singleLineCommentIndex = document.lineAt(position.line).text.indexOf('//'); + if (!isCSS && singleLineCommentIndex > -1 && singleLineCommentIndex < position.character) { + return; + } + + // Go forward until we found a closing brace. + let stream = new DocumentStreamReader(document, position); + while (!stream.eof() && !stream.eat(closeBrace)) { + if (stream.eat(slash)) { + if (stream.eat(slash) && !isCSS) { + // Single line Comment, we continue searching from next line. + stream.pos = new vscode.Position(stream.pos.line + 1, 0); + } else if (stream.eat(star)) { + stream.pos = findClosingCommentAfterPosition(document, stream.pos) || endPosition; + } + } else { + stream.next(); + } + } + + if (!stream.eof()) { + endPosition = stream.pos; + } + + // Go back until we found an opening brace. If we find a closing one, we first find its opening brace and then we continue. + stream.pos = position; + let openBracesRemaining = 1; + let currentLine = position.line; + let limitCharacter = document.offsetAt(position) - 5000; + let limitPosition = limitCharacter > 0 ? document.positionAt(limitCharacter) : startPosition; + + while (openBracesRemaining > 0 && !stream.sof()) { + if (position.line - stream.pos.line > 100 || stream.pos.isBeforeOrEqual(limitPosition)) { + return parseStylesheet(new DocumentStreamReader(document, startPosition, new vscode.Range(startPosition, endPosition))); + } else if (!isCSS && stream.pos.line !== currentLine) { + // In not CSS stylesheets, we need to skip singleLine comments. + currentLine = stream.pos.line; + let startLineComment = document.lineAt(currentLine).text.indexOf('//'); + if (startLineComment > -1) { + stream.pos = new vscode.Position(currentLine, startLineComment); + } + } + let ch = stream.backUp(1); + if (ch === openBrace) { + openBracesRemaining--; + } else if (ch === closeBrace) { + if (isCSS) { + stream.next(); + return parseStylesheet(new DocumentStreamReader(document, stream.pos, new vscode.Range(stream.pos, endPosition))); + } + openBracesRemaining++; + } else if (ch === slash) { + stream.backUp(1); + if (stream.peek() === star) { + stream.pos = findOpeningCommentBeforePosition(document, stream.pos) || startPosition; + } else { + stream.next(); + } + } else if (ch === star) { + stream.backUp(1); + if (stream.peek() === slash) { + return; + } else { + stream.next(); + } + } + } + + // We are at an opening brace. We need to include its selector. + // We need one non whitespace character, that's not commented and is not a block { } + currentLine = stream.pos.line; + openBracesRemaining = 0; + while (!stream.sof()) { + // Find a nonspace character + while (!stream.sof() && String.fromCharCode(stream.backUp(1)).match(/\s/)) { } + if (stream.sof()) { + break; + } + let characterFound = stream.peek(); + // Check if such character is end of comment. + if (characterFound === slash) { + let ch = stream.backUp(1); + if (ch === star) { + stream.pos = findOpeningCommentBeforePosition(document, stream.pos) || startPosition; + } else { + stream.next(); + } + continue; + } + // In not CSS stylesheets, we need to skip singleLine comments. + if (!isCSS && stream.pos.line !== currentLine) { + currentLine = stream.pos.line; + let startLineComment = document.lineAt(currentLine).text.indexOf('//'); + if (startLineComment > -1 && startLineComment < stream.pos.character) { + stream.pos = new vscode.Position(currentLine, startLineComment); + continue; + } + } + // Here, we know we are not in a comment + if (characterFound === closeBrace) { + openBracesRemaining++; + } else if (!openBracesRemaining) { + if (characterFound === openBrace) { + return; + } else { + break; + } + } else if (characterFound === openBrace) { + openBracesRemaining--; + } + } + if (!stream.sof()) { + startPosition = stream.pos; + } + try { + return parseStylesheet(new DocumentStreamReader(document, startPosition, new vscode.Range(startPosition, endPosition))); + } catch (e) { + } +} + +function findOpeningCommentBeforePosition(document: vscode.TextDocument, position: vscode.Position): vscode.Position | undefined { + let text = document.getText(new vscode.Range(0, 0, position.line, position.character)); + let offset = text.lastIndexOf('/*'); + if (offset === -1) { + return; + } + return document.positionAt(offset); +} + +function findClosingCommentAfterPosition(document: vscode.TextDocument, position: vscode.Position): vscode.Position | undefined { + let text = document.getText(new vscode.Range(position.line, position.character, document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length)); + let offset = text.indexOf('*/'); + if (offset === -1) { + return; + } + offset += 2 + document.offsetAt(position); + return document.positionAt(offset); +} + /** * Returns node corresponding to given position in the given root node */ diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index c3bc0c344cf..1bf19c23853 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -2052,9 +2052,9 @@ vinyl@~2.0.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vscode-emmet-helper@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.2.tgz#3df10164b3ee040d90a5216d007fcabbf3e303c7" +vscode-emmet-helper@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.4.tgz#48056974d13036722af019235b9f750a495de728" dependencies: "@emmetio/extract-abbreviation" "0.1.6" jsonc-parser "^1.0.0" diff --git a/extensions/git/package.json b/extensions/git/package.json index 8928bbace19..c4a03271ec2 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -834,6 +834,23 @@ "when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/" } ], + "editor/context": [ + { + "command": "git.stageSelectedRanges", + "group": "2_git@1", + "when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/" + }, + { + "command": "git.unstageSelectedRanges", + "group": "2_git@2", + "when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/" + }, + { + "command": "git.revertSelectedRanges", + "group": "2_git@3", + "when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/" + } + ], "scm/change/title": [ { "command": "git.stageChange", @@ -964,6 +981,12 @@ "scope": "resource", "default": true, "description": "%config.detectSubmodules%" + }, + "git.detectSubmodulesLimit": { + "type": "number", + "scope": "resource", + "default": 10, + "description": "%config.detectSubmodulesLimit%" } } }, @@ -1090,6 +1113,7 @@ "byline": "^5.0.0", "file-type": "^7.2.0", "iconv-lite": "0.4.19", + "jschardet": "^1.6.0", "vscode-extension-telemetry": "0.0.15", "vscode-nls": "^3.2.1", "which": "^1.3.0" @@ -1102,4 +1126,4 @@ "@types/which": "^1.0.28", "mocha": "^3.2.0" } -} \ No newline at end of file +} diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 6910adcbdad..7f2c43dd233 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -70,6 +70,7 @@ "config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.", "config.inputValidation": "Controls when to show commit message input validation.", "config.detectSubmodules": "Controls whether to automatically detect git submodules.", + "config.detectSubmodulesLimit": "Controls the limit of git submodules detected.", "colors.modified": "Color for modified resources.", "colors.deleted": "Color for deleted resources.", "colors.untracked": "Color for untracked resources.", diff --git a/extensions/git/src/api.ts b/extensions/git/src/api.ts index 8d94502e041..6832fda9531 100644 --- a/extensions/git/src/api.ts +++ b/extensions/git/src/api.ts @@ -6,37 +6,55 @@ 'use strict'; import { Model } from './model'; -import { Uri } from 'vscode'; +import { Repository as ModelRepository } from './repository'; +import { Uri, SourceControlInputBox } from 'vscode'; export interface InputBox { value: string; } +export class InputBoxImpl implements InputBox { + set value(value: string) { this.inputBox.value = value; } + get value(): string { return this.inputBox.value; } + constructor(private inputBox: SourceControlInputBox) { } +} + export interface Repository { readonly rootUri: Uri; readonly inputBox: InputBox; } -export interface API { - getRepositories(): Promise; +export class RepositoryImpl implements Repository { + + readonly rootUri: Uri; + readonly inputBox: InputBox; + + constructor(repository: ModelRepository) { + this.rootUri = Uri.file(repository.root); + this.inputBox = new InputBoxImpl(repository.inputBox); + } } -export function createApi(modelPromise: Promise) { - return { - async getRepositories(): Promise { - const model = await modelPromise; +export interface API { + getRepositories(): Promise; + getGitPath(): Promise; +} - return model.repositories.map(repository => ({ - rootUri: Uri.file(repository.root), - inputBox: { - set value(value: string) { - repository.inputBox.value = value; - }, - get value(): string { - return repository.inputBox.value; - } - } - })); - } - }; +export class APIImpl implements API { + + constructor(private modelPromise: Promise) { } + + async getGitPath(): Promise { + const model = await this.modelPromise; + return model.git.path; + } + + async getRepositories(): Promise { + const model = await this.modelPromise; + return model.repositories.map(repository => new RepositoryImpl(repository)); + } +} + +export function createApi(modelPromise: Promise): API { + return new APIImpl(modelPromise); } \ No newline at end of file diff --git a/extensions/git/src/encoding.ts b/extensions/git/src/encoding.ts new file mode 100644 index 00000000000..4396105567f --- /dev/null +++ b/extensions/git/src/encoding.ts @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as jschardet from 'jschardet'; + +jschardet.Constants.MINIMUM_THRESHOLD = 0.2; + +function detectEncodingByBOM(buffer: NodeBuffer): string | null { + if (!buffer || buffer.length < 2) { + return null; + } + + const b0 = buffer.readUInt8(0); + const b1 = buffer.readUInt8(1); + + // UTF-16 BE + if (b0 === 0xFE && b1 === 0xFF) { + return 'utf16be'; + } + + // UTF-16 LE + if (b0 === 0xFF && b1 === 0xFE) { + return 'utf16le'; + } + + if (buffer.length < 3) { + return null; + } + + const b2 = buffer.readUInt8(2); + + // UTF-8 + if (b0 === 0xEF && b1 === 0xBB && b2 === 0xBF) { + return 'utf8'; + } + + return null; +} + +const IGNORE_ENCODINGS = [ + 'ascii', + 'utf-8', + 'utf-16', + 'utf-32' +]; + +const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = { + 'ibm866': 'cp866', + 'big5': 'cp950' +}; + +export function detectEncoding(buffer: Buffer): string | null { + let result = detectEncodingByBOM(buffer); + + if (result) { + return result; + } + + const detected = jschardet.detect(buffer); + + if (!detected || !detected.encoding) { + return null; + } + + const encoding = detected.encoding; + + // Ignore encodings that cannot guess correctly + // (http://chardet.readthedocs.io/en/latest/supported-encodings.html) + if (0 <= IGNORE_ENCODINGS.indexOf(encoding.toLowerCase())) { + return null; + } + + const normalizedEncodingName = encoding.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); + const mapped = JSCHARDET_TO_ICONV_ENCODINGS[normalizedEncodingName]; + + return mapped || normalizedEncodingName; +} diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 094bf3fe577..dc4829808b4 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -15,6 +15,7 @@ import iconv = require('iconv-lite'); import * as filetype from 'file-type'; import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util'; import { CancellationToken } from 'vscode'; +import { detectEncoding } from './encoding'; const readfile = denodeify(fs.readFile); @@ -366,14 +367,14 @@ function getGitErrorCode(stderr: string): string | undefined { export class Git { - private gitPath: string; + readonly path: string; private env: any; private _onOutput = new EventEmitter(); get onOutput(): EventEmitter { return this._onOutput; } constructor(options: IGitOptions) { - this.gitPath = options.gitPath; + this.path = options.gitPath; this.env = options.env || {}; } @@ -447,7 +448,7 @@ export class Git { } spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess { - if (!this.gitPath) { + if (!this.path) { throw new Error('git could not be found in the system.'); } @@ -469,7 +470,7 @@ export class Git { this.log(`> git ${args.join(' ')}\n`); } - return cp.spawn(this.gitPath, args, options); + return cp.spawn(this.path, args, options); } private log(output: string): void { @@ -659,9 +660,16 @@ export class Repository { return result.stdout; } - async bufferString(object: string, encoding: string = 'utf8'): Promise { + async bufferString(object: string, encoding: string = 'utf8', autoGuessEncoding = false): Promise { const stdout = await this.buffer(object); - return iconv.decode(stdout, iconv.encodingExists(encoding) ? encoding : 'utf8'); + + if (autoGuessEncoding) { + encoding = detectEncoding(stdout) || encoding; + } + + encoding = iconv.encodingExists(encoding) ? encoding : 'utf8'; + + return iconv.decode(stdout, encoding); } async buffer(object: string): Promise { diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index efa25a9b6e8..65036c93a7b 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -66,7 +66,7 @@ export class Model { private disposables: Disposable[] = []; - constructor(private git: Git, private globalState: Memento, private outputChannel: OutputChannel) { + constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) { workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }); @@ -227,14 +227,17 @@ export class Model { const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri })); const originalResourceChangeListener = repository.onDidChangeOriginalResource(uri => this._onDidChangeOriginalResource.fire({ repository, uri })); + const submodulesLimit = workspace + .getConfiguration('git', Uri.file(repository.root)) + .get('detectSubmodulesLimit') as number; + const checkForSubmodules = () => { - if (repository.submodules.length > 10) { + if (repository.submodules.length > submodulesLimit) { window.showWarningMessage(localize('too many submodules', "The '{0}' repository has {1} submodules which won't be opened automatically. You can still open each one individually by opening a file within.", path.basename(repository.root), repository.submodules.length)); statusListener.dispose(); - return; } - this.scanSubmodules(repository); + this.scanSubmodules(repository, submodulesLimit); }; const statusListener = repository.onDidRunGitStatus(checkForSubmodules); @@ -256,7 +259,7 @@ export class Model { this._onDidOpenRepository.fire(repository); } - private scanSubmodules(repository: Repository): void { + private scanSubmodules(repository: Repository, limit: number): void { const shouldScanSubmodules = workspace .getConfiguration('git', Uri.file(repository.root)) .get('detectSubmodules') === true; @@ -266,6 +269,7 @@ export class Model { } repository.submodules + .slice(0, limit) .map(r => path.join(repository.root, r.path)) .forEach(p => this.eventuallyScanPossibleGitRepository(p)); } diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 7586abee7eb..cca9f563060 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -811,24 +811,20 @@ export class Repository implements Disposable { } async show(ref: string, filePath: string): Promise { - return await this.run(Operation.Show, async () => { + return this.run(Operation.Show, () => { const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/'); const configFiles = workspace.getConfiguration('files', Uri.file(filePath)); - const encoding = configFiles.get('encoding'); + const defaultEncoding = configFiles.get('encoding'); + const autoGuessEncoding = configFiles.get('autoGuessEncoding'); - // TODO@joao: Resource config api - return await this.repository.bufferString(`${ref}:${relativePath}`, encoding); + return this.repository.bufferString(`${ref}:${relativePath}`, defaultEncoding, autoGuessEncoding); }); } async buffer(ref: string, filePath: string): Promise { - return await this.run(Operation.Show, async () => { + return this.run(Operation.Show, () => { const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/'); - // const configFiles = workspace.getConfiguration('files', Uri.file(filePath)); - // const encoding = configFiles.get('encoding'); - - // TODO@joao: REsource config api - return await this.repository.buffer(`${ref}:${relativePath}`); + return this.repository.buffer(`${ref}:${relativePath}`); }); } diff --git a/extensions/git/src/typings/jschardet.d.ts b/extensions/git/src/typings/jschardet.d.ts new file mode 100644 index 00000000000..9c553b129eb --- /dev/null +++ b/extensions/git/src/typings/jschardet.d.ts @@ -0,0 +1,11 @@ +declare module 'jschardet' { + export interface IDetectedMap { + encoding: string, + confidence: number + } + export function detect(buffer: NodeBuffer): IDetectedMap; + + export const Constants: { + MINIMUM_THRESHOLD: number, + } +} \ No newline at end of file diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index 747060bcb3f..06a4b992dbb 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -145,6 +145,10 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" +jschardet@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" + json3@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" diff --git a/extensions/html-language-features/.vscode/launch.json b/extensions/html-language-features/.vscode/launch.json index c53a74539eb..28ec3d3dc89 100644 --- a/extensions/html-language-features/.vscode/launch.json +++ b/extensions/html-language-features/.vscode/launch.json @@ -38,7 +38,8 @@ "port": 6045, "protocol": "inspector", "sourceMaps": true, - "outFiles": ["${workspaceFolder}/server/out/**/*.js"] + "outFiles": ["${workspaceFolder}/server/out/**/*.js"], + "restart": true } ] } \ No newline at end of file diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 08cf226af51..b90975f8b4a 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -8,13 +8,13 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, FoldingRangeList, FoldingRange, workspace, FoldingContext } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, FoldingRangeList, FoldingRange, FoldingContext } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams, Disposable, CancellationToken } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { FoldingRangesRequest, FoldingRangeRequestParam } from './protocol/foldingProvider.proposed'; +import { FoldingRangesRequest, FoldingRangeRequestParam } from 'vscode-languageserver-protocol-foldingprovider'; namespace TagCloseRequest { export const type: RequestType = new RequestType('html/tag'); @@ -28,8 +28,6 @@ interface IPackageInfo { let telemetryReporter: TelemetryReporter | null; -let foldingProviderRegistration: Disposable | undefined = void 0; -const foldingSetting = 'html.experimental.syntaxFolding'; export function activate(context: ExtensionContext) { let toDispose = context.subscriptions; @@ -83,14 +81,7 @@ export function activate(context: ExtensionContext) { } }); toDispose.push(disposable); - - initFoldingProvider(); - toDispose.push(workspace.onDidChangeConfiguration(c => { - if (c.affectsConfiguration(foldingSetting)) { - initFoldingProvider(); - } - })); - toDispose.push({ dispose: () => foldingProviderRegistration && foldingProviderRegistration.dispose() }); + toDispose.push(initFoldingProvider()); }); languages.setLanguageConfiguration('html', { @@ -167,34 +158,24 @@ export function activate(context: ExtensionContext) { } }); - function initFoldingProvider() { - let enable = workspace.getConfiguration().get(foldingSetting); - if (enable) { - if (!foldingProviderRegistration) { - foldingProviderRegistration = languages.registerFoldingProvider(documentSelector, { - provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { - const param: FoldingRangeRequestParam = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - maxRanges: context.maxRanges - }; - return client.sendRequest(FoldingRangesRequest.type, param, token).then(res => { - if (res && Array.isArray(res.ranges)) { - return new FoldingRangeList(res.ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.type))); - } - return null; - }, error => { - client.logFailedRequest(FoldingRangesRequest.type, error); - return null; - }); + function initFoldingProvider(): Disposable { + return languages.registerFoldingProvider(documentSelector, { + provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { + const param: FoldingRangeRequestParam = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + maxRanges: context.maxRanges + }; + return client.sendRequest(FoldingRangesRequest.type, param, token).then(res => { + if (res && Array.isArray(res.ranges)) { + return new FoldingRangeList(res.ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.type))); } + return null; + }, error => { + client.logFailedRequest(FoldingRangesRequest.type, error); + return null; }); } - } else { - if (foldingProviderRegistration) { - foldingProviderRegistration.dispose(); - foldingProviderRegistration = void 0; - } - } + }); } } diff --git a/extensions/html-language-features/client/src/protocol/foldingProvider.proposed.ts b/extensions/html-language-features/client/src/protocol/foldingProvider.proposed.ts deleted file mode 100644 index dd420e5e452..00000000000 --- a/extensions/html-language-features/client/src/protocol/foldingProvider.proposed.ts +++ /dev/null @@ -1,94 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TextDocumentIdentifier } from 'vscode-languageserver-types'; -import { RequestType, TextDocumentRegistrationOptions, StaticRegistrationOptions } from 'vscode-languageserver-protocol'; - -// ---- capabilities - -export interface FoldingProviderClientCapabilities { - /** - * The text document client capabilities - */ - textDocument?: { - /** - * Capabilities specific to the foldingProvider - */ - foldingProvider?: { - /** - * Whether implementation supports dynamic registration. If this is set to `true` - * the client supports the new `(FoldingProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - * return value for the corresponding server capability as well. - */ - dynamicRegistration?: boolean; - }; - }; -} - -export interface FoldingProviderOptions { -} - -export interface FoldingProviderServerCapabilities { - /** - * The server provides folding provider support. - */ - foldingProvider?: FoldingProviderOptions | (FoldingProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions); -} - -export interface FoldingRangeList { - /** - * The folding ranges. - */ - ranges: FoldingRange[]; -} - -export enum FoldingRangeType { - /** - * Folding range for a comment - */ - Comment = 'comment', - /** - * Folding range for a imports or includes - */ - Imports = 'imports', - /** - * Folding range for a region (e.g. `#region`) - */ - Region = 'region' -} - -export interface FoldingRange { - - /** - * The start line number - */ - startLine: number; - - /** - * The end line number - */ - endLine: number; - - /** - * The actual color value for this folding range. - */ - type?: FoldingRangeType | string; -} - -export interface FoldingRangeRequestParam { - /** - * The text document. - */ - textDocument: TextDocumentIdentifier; - - /** - * The maximum number of ranges to provide - */ - maxRanges?: number; -} - -export namespace FoldingRangesRequest { - export const type: RequestType = new RequestType('textDocument/foldingRanges'); -} diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 0e464eb8bd4..c36e609a75b 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -1,7 +1,7 @@ { "name": "html-language-features", "displayName": "%displayName%", - "description": "%description%", + "description": "%description%", "version": "1.0.0", "publisher": "vscode", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", @@ -17,7 +17,7 @@ "enableProposedApi": true, "main": "./client/out/htmlMain", "scripts": { - "compile": "gulp compile-extension:html-language-features-client && gulp compile-extension:html-language-features-server", + "compile": "gulp compile-extension:html-language-features-client & gulp compile-extension:html-language-features-server", "postinstall": "cd server && yarn install", "install-client-next": "yarn add vscode-languageclient@next" }, @@ -154,11 +154,6 @@ "default": true, "description": "%html.autoClosingTags%" }, - "html.experimental.syntaxFolding": { - "type": "boolean", - "default": false, - "description": "%html.experimental.syntaxFolding%" - }, "html.trace.server": { "type": "string", "scope": "window", @@ -176,6 +171,7 @@ "dependencies": { "vscode-extension-telemetry": "0.0.15", "vscode-languageclient": "^4.0.0", + "vscode-languageserver-protocol-foldingprovider": "^1.0.1", "vscode-nls": "^3.2.2" }, "devDependencies": { diff --git a/extensions/html-language-features/package.nls.json b/extensions/html-language-features/package.nls.json index b41b1236299..4b59c6fba33 100644 --- a/extensions/html-language-features/package.nls.json +++ b/extensions/html-language-features/package.nls.json @@ -22,6 +22,5 @@ "html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.", "html.validate.scripts": "Configures if the built-in HTML language support validates embedded scripts.", "html.validate.styles": "Configures if the built-in HTML language support validates embedded styles.", - "html.experimental.syntaxFolding": "Enables/disables syntax aware folding markers.", "html.autoClosingTags": "Enable/disable autoclosing of HTML tags." } \ No newline at end of file diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index ba166f4017c..1a3d47f448c 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,9 +9,10 @@ }, "dependencies": { "vscode-css-languageservice": "^3.0.8", - "vscode-emmet-helper": "1.2.1", - "vscode-html-languageservice": "^2.1.1", + "vscode-emmet-helper": "1.2.4", + "vscode-html-languageservice": "^2.1.2", "vscode-languageserver": "^4.0.0", + "vscode-languageserver-protocol-foldingprovider": "^1.0.1", "vscode-languageserver-types": "^3.6.1", "vscode-nls": "^3.2.2", "vscode-uri": "^1.0.3" @@ -21,8 +22,8 @@ "@types/node": "7.0.43" }, "scripts": { - "compile": "gulp compile-extension:html-server", - "watch": "gulp watch-extension:html-server", + "compile": "gulp compile-extension:html-language-features-server", + "watch": "gulp watch-extension:html-language-features-server", "install-service-next": "yarn add vscode-css-languageservice@next && yarn add vscode-html-languageservice@next", "install-service-local": "npm install ../../../../vscode-css-languageservice -f && npm install ../../../../vscode-html-languageservice -f", "install-server-next": "yarn add vscode-languageserver@next", diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index e22ad15c346..aa1ce562f00 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -19,9 +19,8 @@ import { getDocumentContext } from './utils/documentContext'; import uri from 'vscode-uri'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; import { doComplete as emmetDoComplete, updateExtensionsPath as updateEmmetExtensionsPath, getEmmetCompletionParticipants } from 'vscode-emmet-helper'; -import { getPathCompletionParticipant } from './modes/pathCompletion'; -import { FoldingRangesRequest, FoldingProviderServerCapabilities } from './protocol/foldingProvider.proposed'; +import { FoldingRangesRequest, FoldingProviderServerCapabilities } from 'vscode-languageserver-protocol-foldingprovider'; import { getFoldingRegions } from './modes/htmlFolding'; namespace TagCloseRequest { @@ -95,7 +94,11 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { } } - languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }); + const workspace = { + get settings() { return globalSettings; }, + get folders() { return workspaceFolders; } + }; + languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace); documents.onDidClose(e => { languageModes.onDocumentRemoved(e.document); }); @@ -149,6 +152,7 @@ connection.onInitialized((p) => { } } workspaceFolders = updatedFolders.concat(toAdd); + documents.all().forEach(triggerValidation); }); } }); @@ -158,13 +162,7 @@ let formatterRegistration: Thenable | null = null; // The settings have changed. Is send on server activation as well. connection.onDidChangeConfiguration((change) => { globalSettings = change.settings; - documentSettings = {}; // reset all document settings - languageModes.getAllModes().forEach(m => { - if (m.configure) { - m.configure(change.settings); - } - }); documents.all().forEach(triggerValidation); // dynamically enable & disable the formatter @@ -288,24 +286,12 @@ connection.onCompletion(async (textDocumentPosition, token) => { cachedCompletionList = null; const emmetCompletionList = CompletionList.create([], false); - const pathCompletionList = CompletionList.create([], false); const emmetCompletionParticipant = getEmmetCompletionParticipants(document, textDocumentPosition.position, mode.getId(), emmetSettings, emmetCompletionList); const completionParticipants = [emmetCompletionParticipant]; - // Ideally, fix this in the Language Service side - // Check participants' methods before calling them - if (mode.getId() === 'html') { - const pathCompletionParticipant = getPathCompletionParticipant(document, workspaceFolders, pathCompletionList); - completionParticipants.push(pathCompletionParticipant); - } let settings = await getDocumentSettings(document, () => doComplete.length > 2); let result = doComplete(document, textDocumentPosition.position, settings, completionParticipants); - if (!result) { - result = pathCompletionList; - } else { - result.items.push(...pathCompletionList.items); - } if (emmetCompletionList.isIncomplete) { cachedCompletionList = result; if (hexColorRegex.test(emmetCompletionList.items[0].label) && result.items.some(x => x.label === emmetCompletionList.items[0].label)) { diff --git a/extensions/html-language-features/server/src/modes/cssMode.ts b/extensions/html-language-features/server/src/modes/cssMode.ts index fef5c40b6fc..61f00efdbd5 100644 --- a/extensions/html-language-features/server/src/modes/cssMode.ts +++ b/extensions/html-language-features/server/src/modes/cssMode.ts @@ -5,14 +5,14 @@ 'use strict'; import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; -import { TextDocument, Position, Range } from 'vscode-languageserver-types'; +import { TextDocument, Position, Range, CompletionList } from 'vscode-languageserver-types'; import { getCSSLanguageService, Stylesheet, ICompletionParticipant } from 'vscode-css-languageservice'; -import { LanguageMode, Settings } from './languageModes'; +import { LanguageMode, Workspace } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; import { Color } from 'vscode-languageserver'; import { extractAbbreviation } from 'vscode-emmet-helper'; -export function getCSSMode(documentRegions: LanguageModelCache): LanguageMode { +export function getCSSMode(documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { let cssLanguageService = getCSSLanguageService(); let embeddedCSSDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument('css')); let cssStylesheets = getLanguageModelCache(10, 60, document => cssLanguageService.parseStylesheet(document)); @@ -21,19 +21,16 @@ export function getCSSMode(documentRegions: LanguageModelCache(10, 60, document => htmlLanguageService.parseHTMLDocument(document)); - let completionParticipants: ICompletionParticipant[] = []; return { getId() { return 'html'; }, - configure(options: any) { - globalSettings = options; - }, - doComplete(document: TextDocument, position: Position, settings: Settings = globalSettings, registeredCompletionParticipants?: ICompletionParticipant[]) { - if (registeredCompletionParticipants) { - completionParticipants = registeredCompletionParticipants; - } + doComplete(document: TextDocument, position: Position, settings = workspace.settings, completionParticipants?: ICompletionParticipant[]) { let options = settings && settings.html && settings.html.suggest; let doAutoComplete = settings && settings.html && settings.html.autoClosingTags; if (doAutoComplete) { options.hideAutoCompleteProposals = true; } + let pathCompletionProposals: CompletionItem[] = []; + let participants = [getPathCompletionParticipant(document, workspace.folders, pathCompletionProposals)]; + if (completionParticipants) { + participants.push(...completionParticipants); + } + htmlLanguageService.setCompletionParticipants(participants); const htmlDocument = htmlDocuments.get(document); - htmlLanguageService.setCompletionParticipants(completionParticipants); - - return htmlLanguageService.doComplete(document, position, htmlDocument, options); - }, - setCompletionParticipants(registeredCompletionParticipants: any[]) { - completionParticipants = registeredCompletionParticipants; + let completionList = htmlLanguageService.doComplete(document, position, htmlDocument, options); + completionList.items.push(...pathCompletionProposals); + return completionList; }, doHover(document: TextDocument, position: Position) { return htmlLanguageService.doHover(document, position, htmlDocuments.get(document)); @@ -53,7 +49,7 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService): LanguageM findDocumentSymbols(document: TextDocument) { return htmlLanguageService.findDocumentSymbols(document, htmlDocuments.get(document)); }, - format(document: TextDocument, range: Range, formatParams: FormattingOptions, settings: Settings = globalSettings) { + format(document: TextDocument, range: Range, formatParams: FormattingOptions, settings = workspace.settings) { let formatSettings: HTMLFormatConfiguration = settings && settings.html && settings.html.format; if (formatSettings) { formatSettings = merge(formatSettings, {}); diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index 2e67f8cced4..8243399a8f0 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -6,20 +6,20 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation, Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, MarkedString, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions } from 'vscode-languageserver-types'; -import { LanguageMode, Settings } from './languageModes'; +import { LanguageMode, Settings, Workspace } from './languageModes'; import { getWordAtText, startsWith, isWhitespaceOnly, repeat } from '../utils/strings'; import { HTMLDocumentRegions } from './embeddedSupport'; import * as ts from 'typescript'; import { join } from 'path'; -import { FoldingRange, FoldingRangeType } from '../protocol/foldingProvider.proposed'; +import { FoldingRange, FoldingRangeType } from 'vscode-languageserver-protocol-foldingprovider'; const FILE_NAME = 'vscode://javascript/1'; // the same 'file' is used for all contents const JQUERY_D_TS = join(__dirname, '../../lib/jquery.d.ts'); const JS_WORD_REGEX = /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g; -export function getJavascriptMode(documentRegions: LanguageModelCache): LanguageMode { +export function getJavascriptMode(documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { let jsDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument('javascript')); let compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es6.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic }; @@ -67,9 +67,6 @@ export function getJavascriptMode(documentRegions: LanguageModelCache= rangeStartLine && endLine < rangeEndLine) { let foldingRange: FoldingRange = { startLine, endLine }; - let match = document.getText(curr).match(/^\s*\/(\/\s*#(?:end)?region\b)|([\*\/])/); + let match = document.getText(curr).match(/^\s*\/(?:(\/\s*#(?:end)?region\b)|(\*|\/))/); if (match) { - foldingRange.type = match[1].length ? FoldingRangeType.Region : FoldingRangeType.Comment; + foldingRange.type = match[1] ? FoldingRangeType.Region : FoldingRangeType.Comment; } ranges.push(foldingRange); } diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index 566677026e9..823d608fbae 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -9,8 +9,8 @@ import { CompletionItem, Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range, Hover, DocumentHighlight, CompletionList, Position, FormattingOptions, SymbolInformation } from 'vscode-languageserver-types'; -import { ColorInformation, ColorPresentation, Color } from 'vscode-languageserver'; -import { FoldingRange } from '../protocol/foldingProvider.proposed'; +import { ColorInformation, ColorPresentation, Color, WorkspaceFolder } from 'vscode-languageserver'; +import { FoldingRange } from 'vscode-languageserver-protocol-foldingprovider'; import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache'; import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; @@ -27,16 +27,15 @@ export interface Settings { emmet?: { [key: string]: any }; } -export interface SettingProvider { - getDocumentSettings(textDocument: TextDocument): Thenable; +export interface Workspace { + readonly settings: Settings; + readonly folders: WorkspaceFolder[]; } export interface LanguageMode { getId(): string; - configure?: (options: Settings) => void; doValidation?: (document: TextDocument, settings?: Settings) => Diagnostic[]; - doComplete?: (document: TextDocument, position: Position, settings?: Settings, registeredCompletionParticipants?: any[]) => CompletionList | null; - setCompletionParticipants?: (registeredCompletionParticipants: any[]) => void; + doComplete?: (document: TextDocument, position: Position, settings?: Settings, registeredCompletionParticipants?: any[]) => CompletionList; doResolve?: (document: TextDocument, item: CompletionItem) => CompletionItem; doHover?: (document: TextDocument, position: Position) => Hover | null; doSignatureHelp?: (document: TextDocument, position: Position) => SignatureHelp | null; @@ -69,7 +68,7 @@ export interface LanguageModeRange extends Range { attributeValue?: boolean; } -export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }): LanguageModes { +export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace): LanguageModes { var htmlLanguageService = getHTMLLanguageService(); let documentRegions = getLanguageModelCache(10, 60, document => getDocumentRegions(htmlLanguageService, document)); @@ -78,12 +77,12 @@ export function getLanguageModes(supportedLanguages: { [languageId: string]: boo modelCaches.push(documentRegions); let modes = Object.create(null); - modes['html'] = getHTMLMode(htmlLanguageService); + modes['html'] = getHTMLMode(htmlLanguageService, workspace); if (supportedLanguages['css']) { - modes['css'] = getCSSMode(documentRegions); + modes['css'] = getCSSMode(documentRegions, workspace); } if (supportedLanguages['javascript']) { - modes['javascript'] = getJavascriptMode(documentRegions); + modes['javascript'] = getJavascriptMode(documentRegions, workspace); } return { getModeAtPosition(document: TextDocument, position: Position): LanguageMode | undefined { diff --git a/extensions/html-language-features/server/src/modes/pathCompletion.ts b/extensions/html-language-features/server/src/modes/pathCompletion.ts index 9b2ccbbd8ca..afb5089fbfd 100644 --- a/extensions/html-language-features/server/src/modes/pathCompletion.ts +++ b/extensions/html-language-features/server/src/modes/pathCompletion.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TextDocument, CompletionList, CompletionItemKind, CompletionItem, TextEdit, Range, Position } from 'vscode-languageserver-types'; +import { TextDocument, CompletionItemKind, CompletionItem, TextEdit, Range, Position } from 'vscode-languageserver-types'; import { WorkspaceFolder } from 'vscode-languageserver'; import * as path from 'path'; import * as fs from 'fs'; @@ -15,25 +15,35 @@ import { contains } from '../utils/arrays'; export function getPathCompletionParticipant( document: TextDocument, - workspaceFolders: WorkspaceFolder[] | undefined, - result: CompletionList + workspaceFolders: WorkspaceFolder[], + result: CompletionItem[] ): ICompletionParticipant { return { - onHtmlAttributeValue: ({ tag, attribute, value, range }) => { + onHtmlAttributeValue: ({ tag, position, attribute, value: valueBeforeCursor, range }) => { + const fullValue = getFullValueWithoutQuotes(document, range); - if (shouldDoPathCompletion(tag, attribute, value)) { - if (!workspaceFolders || workspaceFolders.length === 0) { + if (shouldDoPathCompletion(tag, attribute, fullValue)) { + if (workspaceFolders.length === 0) { return; } const workspaceRoot = resolveWorkspaceRoot(document, workspaceFolders); - const suggestions = providePathSuggestions(value, range, URI.parse(document.uri).fsPath, workspaceRoot); - result.items = [...suggestions, ...result.items]; + const paths = providePaths(valueBeforeCursor, URI.parse(document.uri).fsPath, workspaceRoot); + result.push(...paths.map(p => pathToSuggestion(p, valueBeforeCursor, fullValue, range))); } } }; } +function getFullValueWithoutQuotes(document: TextDocument, range: Range) { + const fullValue = document.getText(range); + if (startsWith(fullValue, `'`) || startsWith(fullValue, `"`)) { + return fullValue.slice(1, -1); + } else { + return fullValue; + } +} + function shouldDoPathCompletion(tag: string, attr: string, value: string): boolean { if (startsWith(value, 'http') || startsWith(value, 'https') || startsWith(value, '//')) { return false; @@ -50,59 +60,78 @@ function shouldDoPathCompletion(tag: string, attr: string, value: string): boole return false; } -export function providePathSuggestions(value: string, range: Range, activeDocFsPath: string, root?: string): CompletionItem[] { - if (startsWith(value, '/') && !root) { +/** + * Get a list of path suggestions. Folder suggestions are suffixed with a slash. + */ +function providePaths(valueBeforeCursor: string, activeDocFsPath: string, root?: string): string[] { + if (startsWith(valueBeforeCursor, '/') && !root) { return []; } - let replaceRange: Range; - const lastIndexOfSlash = value.lastIndexOf('/'); - if (lastIndexOfSlash === -1) { - replaceRange = getFullReplaceRange(range); - } else { - const valueAfterLastSlash = value.slice(lastIndexOfSlash + 1); - replaceRange = getReplaceRange(range, valueAfterLastSlash); - } - + const lastIndexOfSlash = valueBeforeCursor.lastIndexOf('/'); let parentDir: string; if (lastIndexOfSlash === -1) { parentDir = path.resolve(root); } else { - const valueBeforeLastSlash = value.slice(0, lastIndexOfSlash + 1); + const valueBeforeLastSlash = valueBeforeCursor.slice(0, lastIndexOfSlash + 1); - parentDir = startsWith(value, '/') + parentDir = startsWith(valueBeforeCursor, '/') ? path.resolve(root, '.' + valueBeforeLastSlash) : path.resolve(activeDocFsPath, '..', valueBeforeLastSlash); } try { return fs.readdirSync(parentDir).map(f => { - if (isDir(path.resolve(parentDir, f))) { - return { - label: f + '/', - kind: CompletionItemKind.Folder, - textEdit: TextEdit.replace(replaceRange, f + '/'), - command: { - title: 'Suggest', - command: 'editor.action.triggerSuggest' - } - }; - } else { - return { - label: f, - kind: CompletionItemKind.File, - textEdit: TextEdit.replace(replaceRange, f) - }; - } + return fs.statSync(path.resolve(parentDir, f)).isDirectory() + ? f + '/' + : f; }); } catch (e) { return []; } } -const isDir = (p: string) => { - return fs.statSync(p).isDirectory(); -}; +function pathToSuggestion(p: string, valueBeforeCursor: string, fullValue: string, range: Range): CompletionItem { + const isDir = p[p.length - 1] === '/'; + + let replaceRange: Range; + const lastIndexOfSlash = valueBeforeCursor.lastIndexOf('/'); + if (lastIndexOfSlash === -1) { + replaceRange = shiftRange(range, 1, -1); + } else { + // For cases where cursor is in the middle of attribute value, like ', { + testCompletionFor('', { items: [ { label: 'location', resultText: '' }, ] }); - assertCompletions('', { + testCompletionFor('', { items: [ { label: 'getJSON', resultText: '' }, ] }); }); +}); - test('Path completion', function (): any { - let testUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/foo.html')).fsPath; +suite('HTML Path Completion', () => { + const triggerSuggestCommand = { + title: 'Suggest', + command: 'editor.action.triggerSuggest' + }; - assertCompletions('
', { + const fixtureRoot = path.resolve(__dirname, 'pathCompletionFixtures'); + const fixtureWorkspace = { name: 'fixture', uri: Uri.file(fixtureRoot).toString() }; + const indexHtmlUri = Uri.file(path.resolve(fixtureRoot, 'index.html')).toString(); + const aboutHtmlUri = Uri.file(path.resolve(fixtureRoot, 'about/about.html')).toString(); + + test('Basics - Correct label/kind/result/command', () => { + testCompletionFor('', /* 8*/'', @@ -206,7 +210,7 @@ suite('Object Folding', () => { /*2*/'
', ]; assertRanges(input, [r(0, 1)]); - }); + }); test('Fold intersecting region', () => { let input = [ @@ -218,7 +222,7 @@ suite('Object Folding', () => { /*5*/'', ]; assertRanges(input, [r(0, 3)]); - }); + }); test('Test limit', () => { diff --git a/extensions/html-language-features/server/src/test/formatting.test.ts b/extensions/html-language-features/server/src/test/formatting.test.ts index d415f66f519..8a7766c3bbe 100644 --- a/extensions/html-language-features/server/src/test/formatting.test.ts +++ b/extensions/html-language-features/server/src/test/formatting.test.ts @@ -17,10 +17,11 @@ import { format } from '../modes/formatting'; suite('HTML Embedded Formatting', () => { function assertFormat(value: string, expected: string, options?: any, formatOptions?: FormattingOptions, message?: string): void { - var languageModes = getLanguageModes({ css: true, javascript: true }); - if (options) { - languageModes.getAllModes().forEach(m => m.configure!(options)); - } + let workspace = { + settings: options, + folders: [{ name: 'foo', uri: 'test://foo' }] + }; + var languageModes = getLanguageModes({ css: true, javascript: true }, workspace); let rangeStartOffset = value.indexOf('|'); let rangeEndOffset; diff --git a/extensions/html-language-features/server/src/test/pathCompletion/pathCompletion.test.ts b/extensions/html-language-features/server/src/test/pathCompletion/pathCompletion.test.ts deleted file mode 100644 index ba9441986f6..00000000000 --- a/extensions/html-language-features/server/src/test/pathCompletion/pathCompletion.test.ts +++ /dev/null @@ -1,237 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import * as assert from 'assert'; -import * as path from 'path'; -import { providePathSuggestions } from '../../modes/pathCompletion'; -import { CompletionItemKind, Range, Position, CompletionItem, TextEdit, Command } from 'vscode-languageserver-types'; - -const fixtureRoot = path.resolve(__dirname, '../../../test/pathCompletionFixtures'); - -function toRange(line: number, startChar: number, endChar: number) { - return Range.create(Position.create(line, startChar), Position.create(line, endChar)); -} -function toTextEdit(line: number, startChar: number, endChar: number, newText: string) { - const range = Range.create(Position.create(line, startChar), Position.create(line, endChar)); - return TextEdit.replace(range, newText); -} - -interface PathSuggestion { - label?: string; - kind?: CompletionItemKind; - textEdit?: TextEdit; - command?: Command; -} - -function assertSuggestions(actual: CompletionItem[], expected: PathSuggestion[]) { - assert.equal(actual.length, expected.length, `Suggestions have length ${actual.length} but should have length ${expected.length}`); - - for (let i = 0; i < expected.length; i++) { - if (expected[i].label) { - assert.equal( - actual[i].label, - expected[i].label, - `Suggestion ${actual[i].label} should have label ${expected[i].label}` - ); - } - if (expected[i].kind) { - assert.equal(actual[i].kind, - expected[i].kind, - `Suggestion ${actual[i].label} has kind ${actual[i].kind} but should have ${expected[i].kind}` - ); - } - if (expected[i].textEdit) { - assert.equal(actual[i].textEdit!.newText, expected[i].textEdit!.newText); - assert.deepEqual(actual[i].textEdit!.range, expected[i].textEdit!.range); - } - if (expected[i].command) { - assert.equal( - actual[i].command!.title, - expected[i].command!.title, - `Suggestion ${actual[i].label} has command title ${actual[i].command!.title} but should have command title ${expected[i].command!.title}` - ); - assert.equal( - actual[i].command!.command, - expected[i].command!.command, - `Suggestion ${actual[i].label} has command ${actual[i].command!.command} but should have command ${expected[i].command!.command}` - ); - } - } -} - -suite('Path Completion - Relative Path:', () => { - const mockRange = toRange(0, 3, 5); - - test('Current Folder', () => { - const value = './'; - const activeFileFsPath = path.resolve(fixtureRoot, 'index.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath); - - assertSuggestions(suggestions, [ - { label: 'about/', kind: CompletionItemKind.Folder }, - { label: 'index.html', kind: CompletionItemKind.File }, - { label: 'src/', kind: CompletionItemKind.Folder } - ]); - }); - - test('Parent Folder:', () => { - const value = '../'; - const activeFileFsPath = path.resolve(fixtureRoot, 'about/about.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath); - - assertSuggestions(suggestions, [ - { label: 'about/', kind: CompletionItemKind.Folder }, - { label: 'index.html', kind: CompletionItemKind.File }, - { label: 'src/', kind: CompletionItemKind.Folder } - ]); - }); - - test('Adjacent Folder:', () => { - const value = '../src/'; - const activeFileFsPath = path.resolve(fixtureRoot, 'about/about.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath); - - assertSuggestions(suggestions, [ - { label: 'feature.js', kind: CompletionItemKind.File }, - { label: 'test.js', kind: CompletionItemKind.File } - ]); - }); -}); - -suite('Path Completion - Absolute Path:', () => { - const mockRange = toRange(0, 3, 5); - - test('Root', () => { - const value = '/'; - const activeFileFsPath1 = path.resolve(fixtureRoot, 'index.html'); - const activeFileFsPath2 = path.resolve(fixtureRoot, 'about/index.html'); - - const suggestions1 = providePathSuggestions(value, mockRange, activeFileFsPath1, fixtureRoot); - const suggestions2 = providePathSuggestions(value, mockRange, activeFileFsPath2, fixtureRoot); - - const verify = (suggestions: CompletionItem[]) => { - assertSuggestions(suggestions, [ - { label: 'about/', kind: CompletionItemKind.Folder }, - { label: 'index.html', kind: CompletionItemKind.File }, - { label: 'src/', kind: CompletionItemKind.Folder } - ]); - }; - - verify(suggestions1); - verify(suggestions2); - }); - - test('Sub Folder', () => { - const value = '/src/'; - const activeFileFsPath = path.resolve(fixtureRoot, 'about/about.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath, fixtureRoot); - - assertSuggestions(suggestions, [ - { label: 'feature.js', kind: CompletionItemKind.File }, - { label: 'test.js', kind: CompletionItemKind.File } - ]); - }); -}); - -suite('Path Completion - Folder Commands:', () => { - const mockRange = toRange(0, 3, 5); - - test('Folder should have command `editor.action.triggerSuggest', () => { - const value = './'; - const activeFileFsPath = path.resolve(fixtureRoot, 'index.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath); - - assertSuggestions(suggestions, [ - { label: 'about/', command: { title: 'Suggest', command: 'editor.action.triggerSuggest' } }, - { label: 'index.html' }, - { label: 'src/', command: { title: 'Suggest', command: 'editor.action.triggerSuggest' } }, - ]); - }); -}); - -suite('Path Completion - Incomplete Path at End:', () => { - const mockRange = toRange(0, 3, 5); - - test('Incomplete Path that starts with slash', () => { - const value = '/src/f'; - const activeFileFsPath = path.resolve(fixtureRoot, 'about/about.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath, fixtureRoot); - - assertSuggestions(suggestions, [ - { label: 'feature.js', kind: CompletionItemKind.File }, - { label: 'test.js', kind: CompletionItemKind.File } - ]); - }); - - test('Incomplete Path that does not start with slash', () => { - const value = '../src/f'; - const activeFileFsPath = path.resolve(fixtureRoot, 'about/about.html'); - const suggestions = providePathSuggestions(value, mockRange, activeFileFsPath, fixtureRoot); - - assertSuggestions(suggestions, [ - { label: 'feature.js', kind: CompletionItemKind.File }, - { label: 'test.js', kind: CompletionItemKind.File } - ]); - }); -}); - -suite('Path Completion - No leading dot or slash:', () => { - - test('Top level completion', () => { - const value = 's'; - const activeFileFsPath = path.resolve(fixtureRoot, 'index.html'); - const range = toRange(0, 3, 5); - const suggestions = providePathSuggestions(value, range, activeFileFsPath, fixtureRoot); - - assertSuggestions(suggestions, [ - { label: 'about/', kind: CompletionItemKind.Folder, textEdit: toTextEdit(0, 4, 4, 'about/') }, - { label: 'index.html', kind: CompletionItemKind.File, textEdit: toTextEdit(0, 4, 4, 'index.html') }, - { label: 'src/', kind: CompletionItemKind.Folder, textEdit: toTextEdit(0, 4, 4, 'src/') } - ]); - }); - - test('src/', () => { - const value = 'src/'; - const activeFileFsPath = path.resolve(fixtureRoot, 'index.html'); - const range = toRange(0, 3, 8); - const suggestions = providePathSuggestions(value, range, activeFileFsPath, fixtureRoot); - - assertSuggestions(suggestions, [ - { label: 'feature.js', kind: CompletionItemKind.File, textEdit: toTextEdit(0, 7, 7, 'feature.js') }, - { label: 'test.js', kind: CompletionItemKind.File, textEdit: toTextEdit(0, 7, 7, 'test.js') } - ]); - }); - - test('src/f', () => { - const value = 'src/f'; - const activeFileFsPath = path.resolve(fixtureRoot, 'index.html'); - const range = toRange(0, 3, 9); - const suggestions = providePathSuggestions(value, range, activeFileFsPath, fixtureRoot); - - assertSuggestions(suggestions, [ - { label: 'feature.js', kind: CompletionItemKind.File, textEdit: toTextEdit(0, 7, 8, 'feature.js') }, - { label: 'test.js', kind: CompletionItemKind.File, textEdit: toTextEdit(0, 7, 8, 'test.js') } - ]); - }); -}); - -suite('Path Completion - TextEdit:', () => { - - test('TextEdit has correct replace text and range', () => { - const value = './'; - const activeFileFsPath = path.resolve(fixtureRoot, 'index.html'); - const range = toRange(0, 3, 5); - const expectedReplaceRange = toRange(0, 4, 4); - - const suggestions = providePathSuggestions(value, range, activeFileFsPath); - - assertSuggestions(suggestions, [ - { textEdit: TextEdit.replace(expectedReplaceRange, 'about/') }, - { textEdit: TextEdit.replace(expectedReplaceRange, 'index.html') }, - { textEdit: TextEdit.replace(expectedReplaceRange, 'src/') }, - ]); - }); -}); diff --git a/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css b/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css new file mode 100644 index 00000000000..adae63e647c --- /dev/null +++ b/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css @@ -0,0 +1,4 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ \ No newline at end of file diff --git a/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.html b/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/extensions/html-language-features/server/src/test/pathCompletionFixtures/index.html b/extensions/html-language-features/server/src/test/pathCompletionFixtures/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js b/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js new file mode 100644 index 00000000000..adae63e647c --- /dev/null +++ b/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js @@ -0,0 +1,4 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ \ No newline at end of file diff --git a/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js b/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js new file mode 100644 index 00000000000..adae63e647c --- /dev/null +++ b/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js @@ -0,0 +1,4 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ \ No newline at end of file diff --git a/extensions/html-language-features/server/src/test/words.test.ts b/extensions/html-language-features/server/src/test/words.test.ts index d0725ccb8fd..55326de01ce 100644 --- a/extensions/html-language-features/server/src/test/words.test.ts +++ b/extensions/html-language-features/server/src/test/words.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import * as words from '../utils/strings'; -suite('Words', () => { +suite('HTML Words', () => { let wordRegex = /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g; diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 77fc6525c95..fa44e61f9bb 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -25,17 +25,17 @@ vscode-css-languageservice@^3.0.8: vscode-languageserver-types "^3.6.1" vscode-nls "^3.2.1" -vscode-emmet-helper@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.1.tgz#dc4a3c83a3f1d48f4e9e1a5cce0e63f24b6eb843" +vscode-emmet-helper@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.4.tgz#48056974d13036722af019235b9f750a495de728" dependencies: "@emmetio/extract-abbreviation" "0.1.6" jsonc-parser "^1.0.0" vscode-languageserver-types "^3.6.0-next.1" -vscode-html-languageservice@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-2.1.1.tgz#11a4e307f3a983d566313039f99bb37656e86cce" +vscode-html-languageservice@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-2.1.2.tgz#a492d4d3baaa88ce015179f1e985d91eddba9904" dependencies: vscode-languageserver-types "^3.6.1" vscode-nls "^3.2.1" @@ -45,6 +45,13 @@ vscode-jsonrpc@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0.tgz#848d56995d5168950d84feb5d9c237ae5c6a02d4" +vscode-languageserver-protocol-foldingprovider@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol-foldingprovider/-/vscode-languageserver-protocol-foldingprovider-1.0.1.tgz#85514aaf8fe905e91bf21e4106e0847f60d40f44" + dependencies: + vscode-languageserver-protocol "^3.6.0" + vscode-languageserver-types "^3.6.0" + vscode-languageserver-protocol@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0.tgz#579642cdcccf74b0cd771c33daa3239acb40d040" diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index ee2790b3586..8adc0154a74 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -44,6 +44,13 @@ vscode-languageclient@^4.0.0: dependencies: vscode-languageserver-protocol "^3.6.0" +vscode-languageserver-protocol-foldingprovider@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol-foldingprovider/-/vscode-languageserver-protocol-foldingprovider-1.0.1.tgz#85514aaf8fe905e91bf21e4106e0847f60d40f44" + dependencies: + vscode-languageserver-protocol "^3.6.0" + vscode-languageserver-types "^3.6.0" + vscode-languageserver-protocol@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0.tgz#579642cdcccf74b0cd771c33daa3239acb40d040" diff --git a/extensions/html/language-configuration.json b/extensions/html/language-configuration.json index 79ce9f9ce41..191f54303f1 100644 --- a/extensions/html/language-configuration.json +++ b/extensions/html/language-configuration.json @@ -13,7 +13,8 @@ { "open": "[", "close": "]"}, { "open": "(", "close": ")" }, { "open": "'", "close": "'" }, - { "open": "\"", "close": "\"" } + { "open": "\"", "close": "\"" }, + { "open": "", "notIn": [ "comment", "string" ]} ], "surroundingPairs": [ { "open": "'", "close": "'" }, diff --git a/extensions/html/package.json b/extensions/html/package.json index 9e3b9aa968d..5bcc9be5877 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -55,6 +55,9 @@ "source.js": "javascript", "source.python": "python", "source.smarty": "smarty" + }, + "tokenTypes": { + "meta.tag string.quoted": "other" } } ], diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 52017171b09..e38054a4a80 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -62,7 +62,8 @@ "tokenTypes": { "entity.name.type.instance.jsdoc": "other", "entity.name.function.tagged-template.js": "other", - "entity.name.function.tagged-template.js.jsx": "other" + "entity.name.function.tagged-template.js.jsx": "other", + "meta.import string.quoted": "other" } }, { @@ -78,7 +79,8 @@ "tokenTypes": { "entity.name.type.instance.jsdoc": "other", "entity.name.function.tagged-template.js": "other", - "entity.name.function.tagged-template.js.jsx": "other" + "entity.name.function.tagged-template.js.jsx": "other", + "meta.import string.quoted": "other" } }, { diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index a8525b380ef..b697edd0f75 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4ef3570784b60450d6baac681cb096fbf1d2397e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/e375f754b1e6d35133b933131121c634ff6a0aeb", "name": "JavaScript (with React support)", "scopeName": "source.js", "patterns": [ @@ -1641,6 +1641,26 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "begin": "(?<=^import|[^\\._$[:alnum:]]import)(?!\\s*[\"'])", + "end": "\\bfrom\\b", + "endCaptures": { + "0": { + "name": "keyword.control.from.js" + } + }, + "patterns": [ + { + "include": "#import-export-declaration" + } + ] + }, { "include": "#import-export-declaration" } @@ -1923,7 +1943,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.js", - "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2495,12 +2515,16 @@ }, { "name": "support.class.builtin.js", - "match": "(?x)(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.js" } }, - "end": "(/)([gimuy]*)", + "end": "(/)([gimsuy]*)", "endCaptures": { "1": { "name": "punctuation.definition.string.end.js" @@ -3429,13 +3453,13 @@ }, { "name": "string.regexp.js", - "begin": "(?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } }, { "name": "keyword.operator.quantifier.regexp", @@ -3472,7 +3503,7 @@ }, { "name": "meta.group.assertion.regexp", - "begin": "(\\()((\\?=)|(\\?!))", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", "beginCaptures": { "0": { "name": "punctuation.definition.group.regexp" }, "1": { "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" } }, "end": "\\)", @@ -4152,7 +4192,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", "patterns": [ { @@ -4212,8 +4252,8 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", - "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", "patterns": [ { "include": "#jsx-tag" @@ -4222,7 +4262,7 @@ }, "jsx-tag": { "name": "meta.tag.js", - "begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", "end": "(/>)|(?:())", "endCaptures": { "1": { @@ -4249,7 +4289,7 @@ }, "patterns": [ { - "begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>)", + "begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>)", "beginCaptures": { "1": { "name": "punctuation.definition.tag.begin.js" @@ -4358,6 +4398,9 @@ "begin": "\\s+", "end": "(?=[/]?>)", "patterns": [ + { + "include": "#comment" + }, { "include": "#jsx-tag-attribute-name" }, diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 33d2c2324fd..485fc113e79 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4ef3570784b60450d6baac681cb096fbf1d2397e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/e375f754b1e6d35133b933131121c634ff6a0aeb", "name": "JavaScript (with React support)", "scopeName": "source.js.jsx", "patterns": [ @@ -1641,6 +1641,26 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "begin": "(?<=^import|[^\\._$[:alnum:]]import)(?!\\s*[\"'])", + "end": "\\bfrom\\b", + "endCaptures": { + "0": { + "name": "keyword.control.from.js.jsx" + } + }, + "patterns": [ + { + "include": "#import-export-declaration" + } + ] + }, { "include": "#import-export-declaration" } @@ -1923,7 +1943,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.js.jsx", - "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js.jsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2495,12 +2515,16 @@ }, { "name": "support.class.builtin.js.jsx", - "match": "(?x)(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.js.jsx" } }, - "end": "(/)([gimuy]*)", + "end": "(/)([gimsuy]*)", "endCaptures": { "1": { "name": "punctuation.definition.string.end.js.jsx" @@ -3429,13 +3453,13 @@ }, { "name": "string.regexp.js.jsx", - "begin": "(?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } }, { "name": "keyword.operator.quantifier.regexp", @@ -3472,7 +3503,7 @@ }, { "name": "meta.group.assertion.regexp", - "begin": "(\\()((\\?=)|(\\?!))", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", "beginCaptures": { "0": { "name": "punctuation.definition.group.regexp" }, "1": { "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" } }, "end": "\\)", @@ -4152,7 +4192,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", "patterns": [ { @@ -4212,8 +4252,8 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", - "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", "patterns": [ { "include": "#jsx-tag" @@ -4222,7 +4262,7 @@ }, "jsx-tag": { "name": "meta.tag.js.jsx", - "begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", "end": "(/>)|(?:())", "endCaptures": { "1": { @@ -4249,7 +4289,7 @@ }, "patterns": [ { - "begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>)", + "begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>)", "beginCaptures": { "1": { "name": "punctuation.definition.tag.begin.js.jsx" @@ -4358,6 +4398,9 @@ "begin": "\\s+", "end": "(?=[/]?>)", "patterns": [ + { + "include": "#comment" + }, { "include": "#jsx-tag-attribute-name" }, diff --git a/extensions/json-language-features/.vscodeignore b/extensions/json-language-features/.vscodeignore index 0441631b575..d30ea9070d5 100644 --- a/extensions/json-language-features/.vscodeignore +++ b/extensions/json-language-features/.vscodeignore @@ -1,6 +1,7 @@ test/** client/tsconfig.json client/src/** +server/bin server/tsconfig.json server/src/** server/node_modules/@types/** \ No newline at end of file diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index 269ad18cc41..78126d24e6d 100644 --- a/extensions/json-language-features/client/src/jsonMain.ts +++ b/extensions/json-language-features/client/src/jsonMain.ts @@ -12,7 +12,7 @@ import { workspace, languages, ExtensionContext, extensions, Uri, LanguageConfig import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, CancellationToken } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { FoldingRangesRequest, FoldingRangeRequestParam } from './protocol/foldingProvider.proposed'; +import { FoldingRangesRequest, FoldingRangeRequestParam } from 'vscode-languageserver-protocol-foldingprovider'; import { hash } from './utils/hash'; @@ -57,9 +57,6 @@ interface JSONSchemaSettings { let telemetryReporter: TelemetryReporter | undefined; -let foldingProviderRegistration: Disposable | undefined = void 0; -const foldingSetting = 'json.experimental.syntaxFolding'; - export function activate(context: ExtensionContext) { let toDispose = context.subscriptions; @@ -130,13 +127,7 @@ export function activate(context: ExtensionContext) { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); - initFoldingProvider(); - toDispose.push(workspace.onDidChangeConfiguration(c => { - if (c.affectsConfiguration(foldingSetting)) { - initFoldingProvider(); - } - })); - toDispose.push({ dispose: () => foldingProviderRegistration && foldingProviderRegistration.dispose() }); + toDispose.push(initFoldingProvider()); }); let languageConfiguration: LanguageConfiguration = { @@ -149,34 +140,24 @@ export function activate(context: ExtensionContext) { languages.setLanguageConfiguration('json', languageConfiguration); languages.setLanguageConfiguration('jsonc', languageConfiguration); - function initFoldingProvider() { - let enable = workspace.getConfiguration().get(foldingSetting); - if (enable) { - if (!foldingProviderRegistration) { - foldingProviderRegistration = languages.registerFoldingProvider(documentSelector, { - provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { - const param: FoldingRangeRequestParam = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - maxRanges: context.maxRanges - }; - return client.sendRequest(FoldingRangesRequest.type, param, token).then(res => { - if (res && Array.isArray(res.ranges)) { - return new FoldingRangeList(res.ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.type))); - } - return null; - }, error => { - client.logFailedRequest(FoldingRangesRequest.type, error); - return null; - }); + function initFoldingProvider(): Disposable { + return languages.registerFoldingProvider(documentSelector, { + provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { + const param: FoldingRangeRequestParam = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + maxRanges: context.maxRanges + }; + return client.sendRequest(FoldingRangesRequest.type, param, token).then(res => { + if (res && Array.isArray(res.ranges)) { + return new FoldingRangeList(res.ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.type))); } + return null; + }, error => { + client.logFailedRequest(FoldingRangesRequest.type, error); + return null; }); } - } else { - if (foldingProviderRegistration) { - foldingProviderRegistration.dispose(); - foldingProviderRegistration = void 0; - } - } + }); } } diff --git a/extensions/json-language-features/client/src/protocol/foldingProvider.proposed.ts b/extensions/json-language-features/client/src/protocol/foldingProvider.proposed.ts deleted file mode 100644 index dd420e5e452..00000000000 --- a/extensions/json-language-features/client/src/protocol/foldingProvider.proposed.ts +++ /dev/null @@ -1,94 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TextDocumentIdentifier } from 'vscode-languageserver-types'; -import { RequestType, TextDocumentRegistrationOptions, StaticRegistrationOptions } from 'vscode-languageserver-protocol'; - -// ---- capabilities - -export interface FoldingProviderClientCapabilities { - /** - * The text document client capabilities - */ - textDocument?: { - /** - * Capabilities specific to the foldingProvider - */ - foldingProvider?: { - /** - * Whether implementation supports dynamic registration. If this is set to `true` - * the client supports the new `(FoldingProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - * return value for the corresponding server capability as well. - */ - dynamicRegistration?: boolean; - }; - }; -} - -export interface FoldingProviderOptions { -} - -export interface FoldingProviderServerCapabilities { - /** - * The server provides folding provider support. - */ - foldingProvider?: FoldingProviderOptions | (FoldingProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions); -} - -export interface FoldingRangeList { - /** - * The folding ranges. - */ - ranges: FoldingRange[]; -} - -export enum FoldingRangeType { - /** - * Folding range for a comment - */ - Comment = 'comment', - /** - * Folding range for a imports or includes - */ - Imports = 'imports', - /** - * Folding range for a region (e.g. `#region`) - */ - Region = 'region' -} - -export interface FoldingRange { - - /** - * The start line number - */ - startLine: number; - - /** - * The end line number - */ - endLine: number; - - /** - * The actual color value for this folding range. - */ - type?: FoldingRangeType | string; -} - -export interface FoldingRangeRequestParam { - /** - * The text document. - */ - textDocument: TextDocumentIdentifier; - - /** - * The maximum number of ranges to provide - */ - maxRanges?: number; -} - -export namespace FoldingRangesRequest { - export const type: RequestType = new RequestType('textDocument/foldingRanges'); -} diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index dc08f255fd6..d7043cb3aa7 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -85,11 +85,6 @@ "default": true, "description": "%json.colorDecorators.enable.desc%", "deprecationMessage": "%json.colorDecorators.enable.deprecationMessage%" - }, - "json.experimental.syntaxFolding": { - "type": "boolean", - "default": false, - "description": "%json.experimental.syntaxFolding%" } } }, @@ -104,6 +99,7 @@ "dependencies": { "vscode-extension-telemetry": "0.0.15", "vscode-languageclient": "^4.0.0", + "vscode-languageserver-protocol-foldingprovider": "^1.0.1", "vscode-nls": "^3.2.2" }, "devDependencies": { diff --git a/extensions/json-language-features/package.nls.json b/extensions/json-language-features/package.nls.json index 3d268d7391f..f9d52e8ebcf 100644 --- a/extensions/json-language-features/package.nls.json +++ b/extensions/json-language-features/package.nls.json @@ -9,6 +9,5 @@ "json.format.enable.desc": "Enable/disable default JSON formatter (requires restart)", "json.tracing.desc": "Traces the communication between VS Code and the JSON language server.", "json.colorDecorators.enable.desc": "Enables or disables color decorators", - "json.colorDecorators.enable.deprecationMessage": "The setting `json.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.", - "json.experimental.syntaxFolding": "Enables/disables syntax aware folding markers." + "json.colorDecorators.enable.deprecationMessage": "The setting `json.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`." } \ No newline at end of file diff --git a/extensions/json-language-features/server/.npmignore b/extensions/json-language-features/server/.npmignore new file mode 100644 index 00000000000..a6661ddb7fc --- /dev/null +++ b/extensions/json-language-features/server/.npmignore @@ -0,0 +1,7 @@ +.vscode/ +out/test/ +out/**/*.js.map +src/ +test/ +tsconfig.json +.gitignore \ No newline at end of file diff --git a/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md new file mode 100644 index 00000000000..27be5ab1bb1 --- /dev/null +++ b/extensions/json-language-features/server/README.md @@ -0,0 +1,173 @@ +# VSCode JSON Language Server + +[![NPM Version](https://img.shields.io/npm/v/vscode-json-languageserver.svg)](https://npmjs.org/package/vscode-json-languageserver) +[![NPM Downloads](https://img.shields.io/npm/dm/vscode-json-languageserver.svg)](https://npmjs.org/package/vscode-json-languageserver) +[![NPM Version](https://img.shields.io/npm/l/vscode-json-languageserver.svg)](https://npmjs.org/package/vscode-json-languageserver) + +The JSON Language server provides language-specific smarts for editing, validating and understanding JSON documents. It runs as a separate executable and implements the [language server protocol](https://microsoft.github.io/language-server-protocol/overview) to be connected by any code editor or IDE. + +## Capabilities + +### Server capabilities + +The JSON language server supports requests on documents of language id `json` and `jsonc`. +- `json` documents are parsed and validated following the [JSON specification](https://tools.ietf.org/html/rfc7159). +- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`) and accepts trailing commas. JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format. + +The server implements the following capabilities of the language server protocol: + +- [Code completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion) for JSON properties and values based on the document's [JSON schema](http://json-schema.org/) or based on existing properties and values used at other places in the document. JSON schemas are configured through the server configuration options. +- [Hover](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover) for values based on descriptions in the document's [JSON schema](http://json-schema.org/). +- [Document Symbols](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) for quick navigation to properties in the document. +- [Document Colors](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentColor) for showing color decorators on values representing colors and [Color Presentation](https://microsoft.github.io/language-server-protocol/specification#textDocument_colorPresentation) for color presentation information to support color pickers. The location of colors is defined by the document's [JSON schema](http://json-schema.org/). All values marked with `"format": "color-hex"` (VSCode specific, non-standard JSON Schema extension) are considered color values. The supported color formats are `#rgb[a]` and `#rrggbb[aa]`. +- [Code Formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) supporting ranges and formatting the whole document. +- [Diagnostics (Validation)](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) are pushed for all open documents + - syntax errors + - structural validation based on the document's [JSON schema](http://json-schema.org/). + +In order to load JSON schemas, the JSON server uses NodeJS `http` and `fs` modules. For all other features, the JSON server only relies on the documents and settings provided by the client through the LSP. + +### Client requirements: + +The JSON language server expects the client to only send requests and notifications for documents of language id `json` and `jsonc`. + +The JSON language server has the following dependencies on the client's capabilities: + +- Code completion requires that the client capability has *snippetSupport*. If not supported by the client, the server will not offer the completion capability. +- Formatting support requires the client to support *dynamicRegistration* for *rangeFormatting*. If not supported by the client, the server will not offer the format capability. + +## Configuration + +### Settings + +Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes. +The server supports the following settings: + +- http + - `proxy`: The URL of the proxy server to use when fetching schema. When undefined or empty, no proxy is used. + - `proxyStrictSSL`: Whether the proxy server certificate should be verified against the list of supplied CAs. + +- json + - `format` + - `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* + - `schema`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content. + - `fileMatch`: an array or file names or paths (separated by `/`). `*` can be used as a wildcard. + - `url`: The URL of the schema, optional when also a schema is provided. + - `schema`: The schema content. + +```json + { + "http": { + "proxy": "", + "proxyStrictSSL": true + }, + "json": { + "format": { + "enable": true + }, + "schemas": [ + { + "fileMatch": [ + "foo.json", + "*.superfoo.json" + ], + "url": "http://json.schemastore.org/foo", + "schema": { + "type": "array" + } + } + ] + } + } +``` + +### Schema configuration and custom schema content delivery + +[JSON schemas](http://json-schema.org/) are essential for code assist, hovers, color decorators to work and are required for structural validation. + +To find the schema for a given JSON document, the server uses the following mechanisms: +- JSON documents can define the schema URL using a `$schema` property +- The settings define a schema association based on the documents URL. Settings can either associate a schema URL to a file or path pattern, and they can directly provide a schema. +- Additionally, schema associations can also be provided by a custom 'schemaAssociations' configuration call. + +Schemas are identified by URLs. To load the content of a schema, the JSON language server tries to load from that URL or path. The following URL schemas are supported: +- `http`, `https`: Loaded using NodeJS's HTTP support. Proxies can be configured through the settings. +- `file`: Loaded using NodeJS's `fs` support. +- `vscode`: Loaded by an LSP call to the client. + +#### Schema associations notification + +In addition to the settings, schemas associations can also be provided through a notification from the client to the server. This notification is a JSON language server specific, non-standardized, extension to the LSP. + +Notification: +- method: 'json/schemaAssociations' +- params: `ISchemaAssociations` defined as follows + +```ts +interface ISchemaAssociations { + [pattern: string]: string[]; +} +``` + - keys: a file names or file path (separated by `/`). `*` can be used as a wildcard. + - values: An array of schema URLs + +#### Schema content request + +The schema content for schema URLs that start with `vscode://` will be requested from the client through an LSP request. This request is a JSON language server specific, non-standardized, extension to the LSP. + +Request: +- method: 'vscode/content' +- params: `string` - The schema URL to request. The server will only ask for URLs that start with `vscode://` +- response: `string` - The content of the schema with the given URL + +#### Schema content change notification + +When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server specific, non-standardized, extension to the LSP. +The server will, as a response, clear the schema content from the cache and reload the schema content when required again. + +Notification: +- method: 'json/schemaContent' +- params: `string` the URL of the schema that has changed. + +## Try + +The JSON language server is shipped with [Visual Studio Code](https://code.visualstudio.com/) as part of the built-in VSCode extension `json-language-features`. The server is started when the first JSON file is opened. The [VSCode JSON documentation](https://code.visualstudio.com/docs/languages/json) for detailed information on the user experience and has more information on how to configure the language support. + +## Integrate + +If you plan to integrate the JSON language server into an editor and IDE, check out [this page](https://microsoft.github.io/language-server-protocol/implementors/tools/) if there's already an LSP client integration available. + +You can also launch the language server as a command and connect to it. +For that, install the `json-language-server` npm module: + +`npm install -g json-language-server` + +Start the language server with the `json-language-server` command. Use a command line argument to specify the prefered communication channel: + +``` +json-language-server --node-ipc +json-language-server --stdio +json-language-server --socket= +``` + +To connect to the server from NodeJS, see Remy Suen's great write-up on [how to communicate with the server](https://github.com/rcjsuen/dockerfile-language-server-nodejs#communicating-with-the-server) through the available communication channels. + +## Participate + +The source code of the JSON language server can be found [VSCode repository](https://github.com/Microsoft/vscode) at [extensions/json-language-features/server](https://github.com/Microsoft/vscode/tree/master/extensions/json-language-features/server). +File issues and pull requests in the [VSCode GitHub Issues](https://github.com/Microsoft/vscode/issues). See the document [How to Contribute](https://github.com/Microsoft/vscode/wiki/How-to-Contribute) on how to build and run from source. + +Most of the functionality of the server is located in libraries: +- [jsonc-parser](https://github.com/Microsoft/node-jsonc-parser) contains the JSON parser and scanner. +- [vscode-json-languageservice](https://github.com/Microsoft/vscode-json-languageservice) contains the implementation of all features as a re-usable library. +- [vscode-languageserver-node](https://github.com/Microsoft/vscode-languageserver-node) contains the implementation of language server for NodeJS. + +Help on any of these projects is very welcome. + +Please see also our [Code of Conduct](CODE_OF_CONDUCT.md). + +## License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the [MIT](LICENSE.txt) License. diff --git a/extensions/json-language-features/server/bin/vscode-json-languageserver b/extensions/json-language-features/server/bin/vscode-json-languageserver new file mode 100644 index 00000000000..a80d7d55b47 --- /dev/null +++ b/extensions/json-language-features/server/bin/vscode-json-languageserver @@ -0,0 +1,6 @@ +#!/usr/bin/env node +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +require("../out/jsonServerMain"); \ No newline at end of file diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 2a45b8fa7bb..caf8c89dbd0 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -1,31 +1,39 @@ { "name": "vscode-json-languageserver", "description": "JSON language server", - "version": "1.0.0", + "version": "1.0.1", "author": "Microsoft Corporation", "license": "MIT", "engines": { "node": "*" }, + "bin": { + "vscode-json-languageserver": "./bin/vscode-json-languageserver" + }, "dependencies": { "jsonc-parser": "^2.0.0-next.1", "request-light": "^0.2.2", - "vscode-json-languageservice": "^3.0.12", + "vscode-json-languageservice": "^3.0.13", "vscode-languageserver": "^4.0.0", + "vscode-languageserver-protocol-foldingprovider": "^1.0.1", "vscode-nls": "^3.2.2", "vscode-uri": "^1.0.3" }, "devDependencies": { - "@types/node": "7.0.43", - "@types/mocha": "2.2.33" + "@types/mocha": "2.2.33", + "@types/node": "7.0.43" }, "scripts": { - "compile": "gulp compile-extension:json-server", - "watch": "gulp watch-extension:json-server", + "prepublishOnly": "npm run clean && npm run test", + "preversion": "npm test", + "compile": "gulp compile-extension:json-language-features-server", + "watch": "gulp watch-extension:json-language-features-server", + "clean": "../../../node_modules/.bin/rimraf out", "install-service-next": "yarn add vscode-json-languageservice@next", "install-service-local": "yarn link vscode-json-languageservice", "install-server-next": "yarn add vscode-languageserver@next", "install-server-local": "yarn link vscode-languageserver-server", - "test": "npm run compile && ../../../node_modules/.bin/mocha" + "test": "npm run compile && ../../../node_modules/.bin/mocha", + "version": "git commit -m \"JSON Language Server $npm_package_version\" package.json" } } diff --git a/extensions/json-language-features/server/src/jsonFolding.ts b/extensions/json-language-features/server/src/jsonFolding.ts index 288df9ec445..4625e721b24 100644 --- a/extensions/json-language-features/server/src/jsonFolding.ts +++ b/extensions/json-language-features/server/src/jsonFolding.ts @@ -6,7 +6,7 @@ import { TextDocument, Position, CancellationToken } from 'vscode-languageserver'; import { createScanner, SyntaxKind, ScanError } from 'jsonc-parser'; -import { FoldingRangeType, FoldingRange, FoldingRangeList } from './protocol/foldingProvider.proposed'; +import { FoldingRangeType, FoldingRange, FoldingRangeList } from 'vscode-languageserver-protocol-foldingprovider'; export function getFoldingRegions(document: TextDocument, maxRanges: number | undefined, cancellationToken: CancellationToken | null) { let ranges: FoldingRange[] = []; diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index 28625bbaae4..79a9782ee9d 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -7,7 +7,7 @@ import { createConnection, IConnection, TextDocuments, TextDocument, InitializeParams, InitializeResult, NotificationType, RequestType, - DocumentRangeFormattingRequest, Disposable, ServerCapabilities, DocumentColorRequest, ColorPresentationRequest + DocumentRangeFormattingRequest, Disposable, ServerCapabilities } from 'vscode-languageserver'; import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light'; @@ -20,7 +20,7 @@ import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, import { getLanguageModelCache } from './languageModelCache'; import { getFoldingRegions } from './jsonFolding'; -import { FoldingRangesRequest, FoldingProviderServerCapabilities } from './protocol/foldingProvider.proposed'; +import { FoldingRangesRequest, FoldingProviderServerCapabilities } from 'vscode-languageserver-protocol-foldingprovider'; interface ISchemaAssociations { [pattern: string]: string[]; @@ -343,7 +343,7 @@ connection.onDocumentRangeFormatting((formatParams, token) => { }, [], `Error while formatting range for ${formatParams.textDocument.uri}`, token); }); -connection.onRequest(DocumentColorRequest.type, (params, token) => { +connection.onDocumentColor((params, token) => { return runSafeAsync(() => { let document = documents.get(params.textDocument.uri); if (document) { @@ -354,7 +354,7 @@ connection.onRequest(DocumentColorRequest.type, (params, token) => { }, [], `Error while computing document colors for ${params.textDocument.uri}`, token); }); -connection.onRequest(ColorPresentationRequest.type, (params, token) => { +connection.onColorPresentation((params, token) => { return runSafe(() => { let document = documents.get(params.textDocument.uri); if (document) { diff --git a/extensions/json-language-features/server/src/protocol/foldingProvider.proposed.ts b/extensions/json-language-features/server/src/protocol/foldingProvider.proposed.ts deleted file mode 100644 index dd420e5e452..00000000000 --- a/extensions/json-language-features/server/src/protocol/foldingProvider.proposed.ts +++ /dev/null @@ -1,94 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TextDocumentIdentifier } from 'vscode-languageserver-types'; -import { RequestType, TextDocumentRegistrationOptions, StaticRegistrationOptions } from 'vscode-languageserver-protocol'; - -// ---- capabilities - -export interface FoldingProviderClientCapabilities { - /** - * The text document client capabilities - */ - textDocument?: { - /** - * Capabilities specific to the foldingProvider - */ - foldingProvider?: { - /** - * Whether implementation supports dynamic registration. If this is set to `true` - * the client supports the new `(FoldingProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - * return value for the corresponding server capability as well. - */ - dynamicRegistration?: boolean; - }; - }; -} - -export interface FoldingProviderOptions { -} - -export interface FoldingProviderServerCapabilities { - /** - * The server provides folding provider support. - */ - foldingProvider?: FoldingProviderOptions | (FoldingProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions); -} - -export interface FoldingRangeList { - /** - * The folding ranges. - */ - ranges: FoldingRange[]; -} - -export enum FoldingRangeType { - /** - * Folding range for a comment - */ - Comment = 'comment', - /** - * Folding range for a imports or includes - */ - Imports = 'imports', - /** - * Folding range for a region (e.g. `#region`) - */ - Region = 'region' -} - -export interface FoldingRange { - - /** - * The start line number - */ - startLine: number; - - /** - * The end line number - */ - endLine: number; - - /** - * The actual color value for this folding range. - */ - type?: FoldingRangeType | string; -} - -export interface FoldingRangeRequestParam { - /** - * The text document. - */ - textDocument: TextDocumentIdentifier; - - /** - * The maximum number of ranges to provide - */ - maxRanges?: number; -} - -export namespace FoldingRangesRequest { - export const type: RequestType = new RequestType('textDocument/foldingRanges'); -} diff --git a/extensions/json-language-features/server/src/test/folding.test.ts b/extensions/json-language-features/server/src/test/folding.test.ts index e61f8f7367d..e72244cfff2 100644 --- a/extensions/json-language-features/server/src/test/folding.test.ts +++ b/extensions/json-language-features/server/src/test/folding.test.ts @@ -32,7 +32,7 @@ function r(startLine: number, endLine: number, type?: string): ExpectedIndentRan return { startLine, endLine, type }; } -suite('Object Folding', () => { +suite('JSON Folding', () => { test('Fold one level', () => { let input = [ /*0*/'{', diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index e57f26945a3..9eb398335bb 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -68,9 +68,9 @@ request-light@^0.2.2: https-proxy-agent "2.1.1" vscode-nls "^2.0.2" -vscode-json-languageservice@^3.0.12: - version "3.0.12" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.0.12.tgz#85258632f2f7718028fbdfbb95b4ad009107b821" +vscode-json-languageservice@^3.0.13: + version "3.0.13" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.0.13.tgz#dd1b7ddfd4f5ca16e2a7adcc7d7f9009ac02319a" dependencies: jsonc-parser "^2.0.0-next.1" vscode-languageserver-types "^3.6.1" @@ -81,6 +81,13 @@ vscode-jsonrpc@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0.tgz#848d56995d5168950d84feb5d9c237ae5c6a02d4" +vscode-languageserver-protocol-foldingprovider@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol-foldingprovider/-/vscode-languageserver-protocol-foldingprovider-1.0.1.tgz#85514aaf8fe905e91bf21e4106e0847f60d40f44" + dependencies: + vscode-languageserver-protocol "^3.6.0" + vscode-languageserver-types "^3.6.0" + vscode-languageserver-protocol@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0.tgz#579642cdcccf74b0cd771c33daa3239acb40d040" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index d7183c2e545..2db2da5dbe9 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -44,6 +44,13 @@ vscode-languageclient@^4.0.0: dependencies: vscode-languageserver-protocol "^3.6.0" +vscode-languageserver-protocol-foldingprovider@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol-foldingprovider/-/vscode-languageserver-protocol-foldingprovider-1.0.1.tgz#85514aaf8fe905e91bf21e4106e0847f60d40f44" + dependencies: + vscode-languageserver-protocol "^3.6.0" + vscode-languageserver-types "^3.6.0" + vscode-languageserver-protocol@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0.tgz#579642cdcccf74b0cd771c33daa3239acb40d040" diff --git a/extensions/json/OSSREADME.json b/extensions/json/OSSREADME.json index 57bcccdcca0..391402b86f4 100644 --- a/extensions/json/OSSREADME.json +++ b/extensions/json/OSSREADME.json @@ -1,6 +1,6 @@ // ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: [{ - "name": "Benvie/JavaScriptNext.tmLanguage", + "name": "Microsoft/vscode-JSON.tmLanguage", "version": "0.0.0", "license": "MIT", "repositoryURL": "https://github.com/Microsoft/vscode-JSON.tmLanguage" diff --git a/extensions/markdown/.vscodeignore b/extensions/markdown-language-features/.vscodeignore similarity index 100% rename from extensions/markdown/.vscodeignore rename to extensions/markdown-language-features/.vscodeignore diff --git a/extensions/markdown/OSSREADME.json b/extensions/markdown-language-features/OSSREADME.json similarity index 100% rename from extensions/markdown/OSSREADME.json rename to extensions/markdown-language-features/OSSREADME.json diff --git a/extensions/markdown/icon.png b/extensions/markdown-language-features/icon.png similarity index 100% rename from extensions/markdown/icon.png rename to extensions/markdown-language-features/icon.png diff --git a/extensions/markdown/media/Preview.svg b/extensions/markdown-language-features/media/Preview.svg similarity index 100% rename from extensions/markdown/media/Preview.svg rename to extensions/markdown-language-features/media/Preview.svg diff --git a/extensions/markdown/media/PreviewOnRightPane_16x.svg b/extensions/markdown-language-features/media/PreviewOnRightPane_16x.svg similarity index 100% rename from extensions/markdown/media/PreviewOnRightPane_16x.svg rename to extensions/markdown-language-features/media/PreviewOnRightPane_16x.svg diff --git a/extensions/markdown/media/PreviewOnRightPane_16x_dark.svg b/extensions/markdown-language-features/media/PreviewOnRightPane_16x_dark.svg similarity index 100% rename from extensions/markdown/media/PreviewOnRightPane_16x_dark.svg rename to extensions/markdown-language-features/media/PreviewOnRightPane_16x_dark.svg diff --git a/extensions/markdown/media/Preview_inverse.svg b/extensions/markdown-language-features/media/Preview_inverse.svg similarity index 100% rename from extensions/markdown/media/Preview_inverse.svg rename to extensions/markdown-language-features/media/Preview_inverse.svg diff --git a/extensions/markdown/media/ViewSource.svg b/extensions/markdown-language-features/media/ViewSource.svg similarity index 100% rename from extensions/markdown/media/ViewSource.svg rename to extensions/markdown-language-features/media/ViewSource.svg diff --git a/extensions/markdown/media/ViewSource_inverse.svg b/extensions/markdown-language-features/media/ViewSource_inverse.svg similarity index 100% rename from extensions/markdown/media/ViewSource_inverse.svg rename to extensions/markdown-language-features/media/ViewSource_inverse.svg diff --git a/extensions/markdown/media/index.js b/extensions/markdown-language-features/media/index.js similarity index 99% rename from extensions/markdown/media/index.js rename to extensions/markdown-language-features/media/index.js index a3f766e0256..d1abff530f4 100644 --- a/extensions/markdown/media/index.js +++ b/extensions/markdown-language-features/media/index.js @@ -529,26 +529,26 @@ module.exports = throttle; /*! no static exports found */ /***/ (function(module, exports) { -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1, eval)("this"); -} catch (e) { - // This works if the window reference is available - if (typeof window === "object") g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || Function("return this")() || (1, eval)("this"); +} catch (e) { + // This works if the window reference is available + if (typeof window === "object") g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; /***/ }), diff --git a/extensions/markdown/media/markdown.css b/extensions/markdown-language-features/media/markdown.css similarity index 100% rename from extensions/markdown/media/markdown.css rename to extensions/markdown-language-features/media/markdown.css diff --git a/extensions/markdown/media/pre.js b/extensions/markdown-language-features/media/pre.js similarity index 100% rename from extensions/markdown/media/pre.js rename to extensions/markdown-language-features/media/pre.js diff --git a/extensions/markdown/media/tomorrow.css b/extensions/markdown-language-features/media/tomorrow.css similarity index 100% rename from extensions/markdown/media/tomorrow.css rename to extensions/markdown-language-features/media/tomorrow.css diff --git a/extensions/markdown/package-lock.json b/extensions/markdown-language-features/package-lock.json similarity index 100% rename from extensions/markdown/package-lock.json rename to extensions/markdown-language-features/package-lock.json diff --git a/extensions/markdown/package.json b/extensions/markdown-language-features/package.json similarity index 98% rename from extensions/markdown/package.json rename to extensions/markdown-language-features/package.json index e2874249bd4..e02fb758ba2 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown-language-features/package.json @@ -277,10 +277,10 @@ ] }, "scripts": { - "compile": "gulp compile-extension:markdown && npm run build-preview", - "watch": "npm run build-preview && gulp watch-extension:markdown", + "compile": "gulp compile-extension:markdown-language-features && npm run build-preview", + "watch": "npm run build-preview && gulp watch-extension:markdown-language-features", "vscode:prepublish": "npm run build-ext && npm run build-preview", - "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown ./tsconfig.json", + "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown-language-features ./tsconfig.json", "build-preview": "webpack --mode development" }, "dependencies": { diff --git a/extensions/markdown/package.nls.json b/extensions/markdown-language-features/package.nls.json similarity index 100% rename from extensions/markdown/package.nls.json rename to extensions/markdown-language-features/package.nls.json diff --git a/extensions/markdown/preview-src/activeLineMarker.ts b/extensions/markdown-language-features/preview-src/activeLineMarker.ts similarity index 100% rename from extensions/markdown/preview-src/activeLineMarker.ts rename to extensions/markdown-language-features/preview-src/activeLineMarker.ts diff --git a/extensions/markdown/preview-src/csp.ts b/extensions/markdown-language-features/preview-src/csp.ts similarity index 100% rename from extensions/markdown/preview-src/csp.ts rename to extensions/markdown-language-features/preview-src/csp.ts diff --git a/extensions/markdown/preview-src/events.ts b/extensions/markdown-language-features/preview-src/events.ts similarity index 100% rename from extensions/markdown/preview-src/events.ts rename to extensions/markdown-language-features/preview-src/events.ts diff --git a/extensions/markdown/preview-src/index.ts b/extensions/markdown-language-features/preview-src/index.ts similarity index 100% rename from extensions/markdown/preview-src/index.ts rename to extensions/markdown-language-features/preview-src/index.ts diff --git a/extensions/markdown/preview-src/loading.ts b/extensions/markdown-language-features/preview-src/loading.ts similarity index 100% rename from extensions/markdown/preview-src/loading.ts rename to extensions/markdown-language-features/preview-src/loading.ts diff --git a/extensions/markdown/preview-src/messaging.ts b/extensions/markdown-language-features/preview-src/messaging.ts similarity index 100% rename from extensions/markdown/preview-src/messaging.ts rename to extensions/markdown-language-features/preview-src/messaging.ts diff --git a/extensions/markdown/preview-src/pre.ts b/extensions/markdown-language-features/preview-src/pre.ts similarity index 100% rename from extensions/markdown/preview-src/pre.ts rename to extensions/markdown-language-features/preview-src/pre.ts diff --git a/extensions/markdown/preview-src/scroll-sync.ts b/extensions/markdown-language-features/preview-src/scroll-sync.ts similarity index 100% rename from extensions/markdown/preview-src/scroll-sync.ts rename to extensions/markdown-language-features/preview-src/scroll-sync.ts diff --git a/extensions/markdown/preview-src/settings.ts b/extensions/markdown-language-features/preview-src/settings.ts similarity index 100% rename from extensions/markdown/preview-src/settings.ts rename to extensions/markdown-language-features/preview-src/settings.ts diff --git a/extensions/markdown/preview-src/strings.ts b/extensions/markdown-language-features/preview-src/strings.ts similarity index 100% rename from extensions/markdown/preview-src/strings.ts rename to extensions/markdown-language-features/preview-src/strings.ts diff --git a/extensions/markdown/preview-src/tsconfig.json b/extensions/markdown-language-features/preview-src/tsconfig.json similarity index 100% rename from extensions/markdown/preview-src/tsconfig.json rename to extensions/markdown-language-features/preview-src/tsconfig.json diff --git a/extensions/markdown/schemas/package.schema.json b/extensions/markdown-language-features/schemas/package.schema.json similarity index 100% rename from extensions/markdown/schemas/package.schema.json rename to extensions/markdown-language-features/schemas/package.schema.json diff --git a/extensions/markdown/src/commandManager.ts b/extensions/markdown-language-features/src/commandManager.ts similarity index 100% rename from extensions/markdown/src/commandManager.ts rename to extensions/markdown-language-features/src/commandManager.ts diff --git a/extensions/markdown/src/commands/index.ts b/extensions/markdown-language-features/src/commands/index.ts similarity index 100% rename from extensions/markdown/src/commands/index.ts rename to extensions/markdown-language-features/src/commands/index.ts diff --git a/extensions/markdown/src/commands/moveCursorToPosition.ts b/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts similarity index 100% rename from extensions/markdown/src/commands/moveCursorToPosition.ts rename to extensions/markdown-language-features/src/commands/moveCursorToPosition.ts diff --git a/extensions/markdown/src/commands/onPreviewStyleLoadError.ts b/extensions/markdown-language-features/src/commands/onPreviewStyleLoadError.ts similarity index 100% rename from extensions/markdown/src/commands/onPreviewStyleLoadError.ts rename to extensions/markdown-language-features/src/commands/onPreviewStyleLoadError.ts diff --git a/extensions/markdown/src/commands/openDocumentLink.ts b/extensions/markdown-language-features/src/commands/openDocumentLink.ts similarity index 100% rename from extensions/markdown/src/commands/openDocumentLink.ts rename to extensions/markdown-language-features/src/commands/openDocumentLink.ts diff --git a/extensions/markdown/src/commands/refreshPreview.ts b/extensions/markdown-language-features/src/commands/refreshPreview.ts similarity index 100% rename from extensions/markdown/src/commands/refreshPreview.ts rename to extensions/markdown-language-features/src/commands/refreshPreview.ts diff --git a/extensions/markdown/src/commands/showPreview.ts b/extensions/markdown-language-features/src/commands/showPreview.ts similarity index 100% rename from extensions/markdown/src/commands/showPreview.ts rename to extensions/markdown-language-features/src/commands/showPreview.ts diff --git a/extensions/markdown/src/commands/showPreviewSecuritySelector.ts b/extensions/markdown-language-features/src/commands/showPreviewSecuritySelector.ts similarity index 100% rename from extensions/markdown/src/commands/showPreviewSecuritySelector.ts rename to extensions/markdown-language-features/src/commands/showPreviewSecuritySelector.ts diff --git a/extensions/markdown/src/commands/showSource.ts b/extensions/markdown-language-features/src/commands/showSource.ts similarity index 73% rename from extensions/markdown/src/commands/showSource.ts rename to extensions/markdown-language-features/src/commands/showSource.ts index 455327599e3..a916bccefc0 100644 --- a/extensions/markdown/src/commands/showSource.ts +++ b/extensions/markdown-language-features/src/commands/showSource.ts @@ -14,15 +14,9 @@ export class ShowSourceCommand implements Command { private readonly previewManager: MarkdownPreviewManager ) { } - - public execute(docUri?: vscode.Uri) { - if (!docUri) { - return vscode.commands.executeCommand('workbench.action.navigateBack'); - } - - const resource = this.previewManager.getResourceForPreview(docUri); - if (resource) { - return vscode.workspace.openTextDocument(resource) + public execute() { + if (this.previewManager.activePreviewResource) { + return vscode.workspace.openTextDocument(this.previewManager.activePreviewResource) .then(document => vscode.window.showTextDocument(document)); } return undefined; diff --git a/extensions/markdown/src/commands/toggleLock.ts b/extensions/markdown-language-features/src/commands/toggleLock.ts similarity index 84% rename from extensions/markdown/src/commands/toggleLock.ts rename to extensions/markdown-language-features/src/commands/toggleLock.ts index 384138a10e1..a6596e5e27c 100644 --- a/extensions/markdown/src/commands/toggleLock.ts +++ b/extensions/markdown-language-features/src/commands/toggleLock.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; import { Command } from '../commandManager'; import { MarkdownPreviewManager } from '../features/previewManager'; @@ -14,7 +13,7 @@ export class ToggleLockCommand implements Command { private readonly previewManager: MarkdownPreviewManager ) { } - public execute(previewUri?: vscode.Uri) { - this.previewManager.toggleLock(previewUri); + public execute() { + this.previewManager.toggleLock(); } } \ No newline at end of file diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown-language-features/src/extension.ts similarity index 100% rename from extensions/markdown/src/extension.ts rename to extensions/markdown-language-features/src/extension.ts diff --git a/extensions/markdown/src/features/documentLinkProvider.ts b/extensions/markdown-language-features/src/features/documentLinkProvider.ts similarity index 100% rename from extensions/markdown/src/features/documentLinkProvider.ts rename to extensions/markdown-language-features/src/features/documentLinkProvider.ts diff --git a/extensions/markdown/src/features/documentSymbolProvider.ts b/extensions/markdown-language-features/src/features/documentSymbolProvider.ts similarity index 100% rename from extensions/markdown/src/features/documentSymbolProvider.ts rename to extensions/markdown-language-features/src/features/documentSymbolProvider.ts diff --git a/extensions/markdown/src/features/foldingProvider.ts b/extensions/markdown-language-features/src/features/foldingProvider.ts similarity index 100% rename from extensions/markdown/src/features/foldingProvider.ts rename to extensions/markdown-language-features/src/features/foldingProvider.ts diff --git a/extensions/markdown/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts similarity index 92% rename from extensions/markdown/src/features/preview.ts rename to extensions/markdown-language-features/src/features/preview.ts index 5aef6b80c8f..1002bcf0fc5 100644 --- a/extensions/markdown/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -18,10 +18,8 @@ const localize = nls.loadMessageBundle(); export class MarkdownPreview { - public static previewScheme = 'vscode-markdown-preview'; - private static previewCount = 0; + public static previewViewType = 'markdown.preview'; - public readonly uri: vscode.Uri; private readonly webview: vscode.Webview; private throttleTimer: any; private initialLine: number | undefined = undefined; @@ -41,13 +39,13 @@ export class MarkdownPreview { topmostLineMonitor: MarkdownFileTopmostLineMonitor, private readonly contributions: MarkdownContributions ) { - this.uri = vscode.Uri.parse(`${MarkdownPreview.previewScheme}:${MarkdownPreview.previewCount++}`); this.webview = vscode.window.createWebview( - this.uri, + MarkdownPreview.previewViewType, this.getPreviewTitle(this._resource), previewColumn, { enableScripts: true, enableCommandUris: true, + enableFindWidget: true, localResourceRoots: this.getLocalResourceRoots(_resource) }); @@ -55,8 +53,8 @@ export class MarkdownPreview { this.dispose(); }, null, this.disposables); - this.webview.onDidChangeViewColumn(() => { - this._onDidChangeViewColumnEmitter.fire(); + this.webview.onDidChangeViewState(e => { + this._onDidChangeViewStateEmitter.fire(e); }, null, this.disposables); this.webview.onDidReceiveMessage(e => { @@ -106,8 +104,8 @@ export class MarkdownPreview { private readonly _onDisposeEmitter = new vscode.EventEmitter(); public readonly onDispose = this._onDisposeEmitter.event; - private readonly _onDidChangeViewColumnEmitter = new vscode.EventEmitter(); - public readonly onDidChangeViewColumn = this._onDidChangeViewColumnEmitter.event; + private readonly _onDidChangeViewStateEmitter = new vscode.EventEmitter(); + public readonly onDidChangeViewState = this._onDidChangeViewStateEmitter.event; public get resource(): vscode.Uri { return this._resource; @@ -117,7 +115,7 @@ export class MarkdownPreview { this._onDisposeEmitter.fire(); this._onDisposeEmitter.dispose(); - this._onDidChangeViewColumnEmitter.dispose(); + this._onDidChangeViewStateEmitter.dispose(); this.webview.dispose(); disposeAll(this.disposables); @@ -191,8 +189,8 @@ export class MarkdownPreview { return this.matchesResource(otherPreview._resource, otherPreview.viewColumn, otherPreview.locked); } - public show(viewColumn: vscode.ViewColumn) { - this.webview.show(viewColumn); + public reveal(viewColumn: vscode.ViewColumn) { + this.webview.reveal(viewColumn); } public toggleLock() { diff --git a/extensions/markdown/src/features/previewConfig.ts b/extensions/markdown-language-features/src/features/previewConfig.ts similarity index 100% rename from extensions/markdown/src/features/previewConfig.ts rename to extensions/markdown-language-features/src/features/previewConfig.ts diff --git a/extensions/markdown/src/features/previewContentProvider.ts b/extensions/markdown-language-features/src/features/previewContentProvider.ts similarity index 93% rename from extensions/markdown/src/features/previewContentProvider.ts rename to extensions/markdown-language-features/src/features/previewContentProvider.ts index 7652d5aa3cb..e2cbae775bf 100644 --- a/extensions/markdown/src/features/previewContentProvider.ts +++ b/extensions/markdown-language-features/src/features/previewContentProvider.ts @@ -164,6 +164,9 @@ export class MarkdownContentProvider { case MarkdownPreviewSecurityLevel.AllowInsecureContent: return ``; + case MarkdownPreviewSecurityLevel.AllowInsecureLocalContent: + return ``; + case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent: return ''; diff --git a/extensions/markdown/src/features/previewManager.ts b/extensions/markdown-language-features/src/features/previewManager.ts similarity index 79% rename from extensions/markdown/src/features/previewManager.ts rename to extensions/markdown-language-features/src/features/previewManager.ts index 08f5e0277b2..61fee517b43 100644 --- a/extensions/markdown/src/features/previewManager.ts +++ b/extensions/markdown-language-features/src/features/previewManager.ts @@ -28,15 +28,8 @@ export class MarkdownPreviewManager { private readonly logger: Logger, private readonly contributions: MarkdownContributions ) { - vscode.window.onDidChangeActiveEditor(editor => { - vscode.commands.executeCommand('setContext', MarkdownPreviewManager.markdownPreviewActiveContextKey, - editor && editor.editorType === 'webview' && editor.uri.scheme === MarkdownPreview.previewScheme); - - this.activePreview = editor && editor.editorType === 'webview' - ? this.previews.find(preview => editor.uri.toString() === preview.uri.toString()) - : undefined; - - if (editor && editor.editorType === 'texteditor') { + vscode.window.onDidChangeActiveTextEditor(editor => { + if (editor) { if (isMarkdownFile(editor.document)) { for (const preview of this.previews.filter(preview => !preview.locked)) { preview.update(editor.document.uri); @@ -44,6 +37,7 @@ export class MarkdownPreviewManager { } } }, null, this.disposables); + } public dispose(): void { @@ -69,7 +63,7 @@ export class MarkdownPreviewManager { ): void { let preview = this.getExistingPreview(resource, previewSettings); if (preview) { - preview.show(previewSettings.previewColumn); + preview.reveal(previewSettings.previewColumn); } else { preview = this.createNewPreview(resource, previewSettings); this.previews.push(preview); @@ -82,13 +76,8 @@ export class MarkdownPreviewManager { return this.activePreview && this.activePreview.resource; } - public getResourceForPreview(previewUri: vscode.Uri): vscode.Uri | undefined { - const preview = this.getPreviewWithUri(previewUri); - return preview && preview.resource; - } - - public toggleLock(previewUri?: vscode.Uri) { - const preview = previewUri ? this.getPreviewWithUri(previewUri) : this.activePreview; + public toggleLock() { + const preview = this.activePreview; if (preview) { preview.toggleLock(); @@ -109,10 +98,6 @@ export class MarkdownPreviewManager { preview.matchesResource(resource, previewSettings.previewColumn, previewSettings.locked)); } - private getPreviewWithUri(previewUri: vscode.Uri): MarkdownPreview | undefined { - return this.previews.find(preview => preview.uri.toString() === previewUri.toString()); - } - private createNewPreview( resource: vscode.Uri, previewSettings: PreviewSettings @@ -134,8 +119,13 @@ export class MarkdownPreviewManager { } }); - preview.onDidChangeViewColumn(() => { + preview.onDidChangeViewState(({ active }) => { disposeAll(this.previews.filter(otherPreview => preview !== otherPreview && preview!.matches(otherPreview))); + + vscode.commands.executeCommand('setContext', MarkdownPreviewManager.markdownPreviewActiveContextKey, + active); + + this.activePreview = active ? preview : undefined; }); return preview; diff --git a/extensions/markdown/src/logger.ts b/extensions/markdown-language-features/src/logger.ts similarity index 100% rename from extensions/markdown/src/logger.ts rename to extensions/markdown-language-features/src/logger.ts diff --git a/extensions/markdown/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts similarity index 100% rename from extensions/markdown/src/markdownEngine.ts rename to extensions/markdown-language-features/src/markdownEngine.ts diff --git a/extensions/markdown/src/markdownExtensions.ts b/extensions/markdown-language-features/src/markdownExtensions.ts similarity index 100% rename from extensions/markdown/src/markdownExtensions.ts rename to extensions/markdown-language-features/src/markdownExtensions.ts diff --git a/extensions/markdown/src/security.ts b/extensions/markdown-language-features/src/security.ts similarity index 93% rename from extensions/markdown/src/security.ts rename to extensions/markdown-language-features/src/security.ts index ef04896bec3..a09ce1f538a 100644 --- a/extensions/markdown/src/security.ts +++ b/extensions/markdown-language-features/src/security.ts @@ -14,7 +14,8 @@ const localize = nls.loadMessageBundle(); export enum MarkdownPreviewSecurityLevel { Strict = 0, AllowInsecureContent = 1, - AllowScriptsAndAllContent = 2 + AllowScriptsAndAllContent = 2, + AllowInsecureLocalContent = 3 } export interface ContentSecurityPolicyArbiter { @@ -109,6 +110,10 @@ export class PreviewSecuritySelector { type: MarkdownPreviewSecurityLevel.Strict, label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.Strict) + localize('strict.title', 'Strict'), description: localize('strict.description', 'Only load secure content'), + }, { + type: MarkdownPreviewSecurityLevel.AllowInsecureLocalContent, + label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureLocalContent) + localize('insecureLocalContent.title', 'Allow insecure local content'), + description: localize('insecureLocalContent.description', 'Enable loading content over http served from localhost'), }, { type: MarkdownPreviewSecurityLevel.AllowInsecureContent, label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureContent) + localize('insecureContent.title', 'Allow insecure content'), @@ -133,7 +138,6 @@ export class PreviewSecuritySelector { 'preview.showPreviewSecuritySelector.title', 'Select security settings for Markdown previews in this workspace'), }); - if (!selection) { return; } diff --git a/extensions/markdown/src/tableOfContentsProvider.ts b/extensions/markdown-language-features/src/tableOfContentsProvider.ts similarity index 100% rename from extensions/markdown/src/tableOfContentsProvider.ts rename to extensions/markdown-language-features/src/tableOfContentsProvider.ts diff --git a/extensions/markdown/src/telemetryReporter.ts b/extensions/markdown-language-features/src/telemetryReporter.ts similarity index 100% rename from extensions/markdown/src/telemetryReporter.ts rename to extensions/markdown-language-features/src/telemetryReporter.ts diff --git a/extensions/markdown/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts similarity index 100% rename from extensions/markdown/src/test/foldingProvider.test.ts rename to extensions/markdown-language-features/src/test/foldingProvider.test.ts diff --git a/extensions/markdown/src/test/inMemoryDocument.ts b/extensions/markdown-language-features/src/test/inMemoryDocument.ts similarity index 100% rename from extensions/markdown/src/test/inMemoryDocument.ts rename to extensions/markdown-language-features/src/test/inMemoryDocument.ts diff --git a/extensions/markdown/src/test/index.ts b/extensions/markdown-language-features/src/test/index.ts similarity index 100% rename from extensions/markdown/src/test/index.ts rename to extensions/markdown-language-features/src/test/index.ts diff --git a/extensions/markdown/src/test/tableOfContentsProvider.test.ts b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts similarity index 100% rename from extensions/markdown/src/test/tableOfContentsProvider.test.ts rename to extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts diff --git a/extensions/markdown/src/typings/markdown-it-named-headers.d.ts b/extensions/markdown-language-features/src/typings/markdown-it-named-headers.d.ts similarity index 100% rename from extensions/markdown/src/typings/markdown-it-named-headers.d.ts rename to extensions/markdown-language-features/src/typings/markdown-it-named-headers.d.ts diff --git a/extensions/markdown/src/typings/ref.d.ts b/extensions/markdown-language-features/src/typings/ref.d.ts similarity index 100% rename from extensions/markdown/src/typings/ref.d.ts rename to extensions/markdown-language-features/src/typings/ref.d.ts diff --git a/extensions/markdown/src/util/dispose.ts b/extensions/markdown-language-features/src/util/dispose.ts similarity index 100% rename from extensions/markdown/src/util/dispose.ts rename to extensions/markdown-language-features/src/util/dispose.ts diff --git a/extensions/markdown/src/util/file.ts b/extensions/markdown-language-features/src/util/file.ts similarity index 100% rename from extensions/markdown/src/util/file.ts rename to extensions/markdown-language-features/src/util/file.ts diff --git a/extensions/markdown/src/util/topmostLineMonitor.ts b/extensions/markdown-language-features/src/util/topmostLineMonitor.ts similarity index 100% rename from extensions/markdown/src/util/topmostLineMonitor.ts rename to extensions/markdown-language-features/src/util/topmostLineMonitor.ts diff --git a/extensions/markdown/tsconfig.json b/extensions/markdown-language-features/tsconfig.json similarity index 100% rename from extensions/markdown/tsconfig.json rename to extensions/markdown-language-features/tsconfig.json diff --git a/extensions/markdown/webpack.config.js b/extensions/markdown-language-features/webpack.config.js similarity index 100% rename from extensions/markdown/webpack.config.js rename to extensions/markdown-language-features/webpack.config.js diff --git a/extensions/markdown/yarn.lock b/extensions/markdown-language-features/yarn.lock similarity index 100% rename from extensions/markdown/yarn.lock rename to extensions/markdown-language-features/yarn.lock diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 00de7090ed1..ee072978725 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -100,17 +100,22 @@ async function provideNpmScripts(): Promise { let emptyTasks: vscode.Task[] = []; let allTasks: vscode.Task[] = []; - let paths = await vscode.workspace.findFiles('**/package.json', '**/node_modules/**'); - if (paths.length === 0) { + let folders = vscode.workspace.workspaceFolders; + if (!folders) { return emptyTasks; } - try { - for (let i = 0; i < paths.length; i++) { - let folder = vscode.workspace.getWorkspaceFolder(paths[i]); - if (folder && isEnabled(folder) && !isExcluded(folder, paths[i])) { - let tasks = await provideNpmScriptsForFolder(paths[i]); - allTasks.push(...tasks); + for (let i = 0; i < folders.length; i++) { + let folder = folders[i]; + if (isEnabled(folder)) { + let relativePattern = new vscode.RelativePattern(folder, '**/package.json'); + let paths = await vscode.workspace.findFiles(relativePattern, '**/node_modules/**'); + for (let j = 0; j < paths.length; j++) { + if (!isExcluded(folder, paths[j])) { + let tasks = await provideNpmScriptsForFolder(paths[j]); + allTasks.push(...tasks); + } + } } } return allTasks; diff --git a/extensions/package.json b/extensions/package.json index 97fd5f8b0e9..efc4da072e5 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "2.7.2" + "typescript": "2.8.1" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/php/icons/logo.png b/extensions/php-language-features/icons/logo.png similarity index 100% rename from extensions/php/icons/logo.png rename to extensions/php-language-features/icons/logo.png diff --git a/extensions/php-language-features/package.json b/extensions/php-language-features/package.json new file mode 100644 index 00000000000..da6ccc93199 --- /dev/null +++ b/extensions/php-language-features/package.json @@ -0,0 +1,82 @@ +{ + "name": "php-language-features", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.0", + "publisher": "vscode", + "icon": "icons/logo.png", + "engines": { + "vscode": "0.10.x" + }, + "activationEvents": [ + "onLanguage:php" + ], + "main": "./out/phpMain", + "dependencies": { + "vscode-nls": "^3.2.1" + }, + "contributes": { + "configuration": { + "title": "%configuration.title%", + "type": "object", + "order": 20, + "properties": { + "php.suggest.basic": { + "type": "boolean", + "default": true, + "description": "%configuration.suggest.basic%" + }, + "php.validate.enable": { + "type": "boolean", + "default": true, + "description": "%configuration.validate.enable%" + }, + "php.validate.executablePath": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "%configuration.validate.executablePath%" + }, + "php.validate.run": { + "type": "string", + "enum": [ + "onSave", + "onType" + ], + "default": "onSave", + "description": "%configuration.validate.run%" + } + } + }, + "jsonValidation": [ + { + "fileMatch": "composer.json", + "url": "https://getcomposer.org/schema.json" + } + ], + "commands": [ + { + "title": "%command.untrustValidationExecutable%", + "category": "%commands.categroy.php%", + "command": "php.untrustValidationExecutable" + } + ], + "menus": { + "commandPalette": [ + { + "command": "php.untrustValidationExecutable", + "when": "php.untrustValidationExecutableContext" + } + ] + } + }, + "scripts": { + "compile": "gulp compile-extension:php", + "watch": "gulp watch-extension:php" + }, + "devDependencies": { + "@types/node": "7.0.43" + } +} diff --git a/extensions/php-language-features/package.nls.json b/extensions/php-language-features/package.nls.json new file mode 100644 index 00000000000..c991103e41d --- /dev/null +++ b/extensions/php-language-features/package.nls.json @@ -0,0 +1,11 @@ +{ + "configuration.suggest.basic": "Configures if the built-in PHP language suggestions are enabled. The support suggests PHP globals and variables.", + "configuration.validate.enable": "Enable/disable built-in PHP validation.", + "configuration.validate.executablePath": "Points to the PHP executable.", + "configuration.validate.run": "Whether the linter is run on save or on type.", + "configuration.title": "PHP", + "commands.categroy.php": "PHP", + "command.untrustValidationExecutable": "Disallow PHP validation executable (defined as workspace setting)", + "displayName": "PHP Language Features", + "description": "Provides rich language support for PHP files." +} \ No newline at end of file diff --git a/extensions/php/src/features/completionItemProvider.ts b/extensions/php-language-features/src/features/completionItemProvider.ts similarity index 100% rename from extensions/php/src/features/completionItemProvider.ts rename to extensions/php-language-features/src/features/completionItemProvider.ts diff --git a/extensions/php/src/features/hoverProvider.ts b/extensions/php-language-features/src/features/hoverProvider.ts similarity index 100% rename from extensions/php/src/features/hoverProvider.ts rename to extensions/php-language-features/src/features/hoverProvider.ts diff --git a/extensions/php/src/features/phpGlobals.ts b/extensions/php-language-features/src/features/phpGlobals.ts similarity index 100% rename from extensions/php/src/features/phpGlobals.ts rename to extensions/php-language-features/src/features/phpGlobals.ts diff --git a/extensions/php/src/features/signatureHelpProvider.ts b/extensions/php-language-features/src/features/signatureHelpProvider.ts similarity index 100% rename from extensions/php/src/features/signatureHelpProvider.ts rename to extensions/php-language-features/src/features/signatureHelpProvider.ts diff --git a/extensions/php/src/features/utils/async.ts b/extensions/php-language-features/src/features/utils/async.ts similarity index 100% rename from extensions/php/src/features/utils/async.ts rename to extensions/php-language-features/src/features/utils/async.ts diff --git a/extensions/php/src/features/utils/markedTextUtil.ts b/extensions/php-language-features/src/features/utils/markedTextUtil.ts similarity index 100% rename from extensions/php/src/features/utils/markedTextUtil.ts rename to extensions/php-language-features/src/features/utils/markedTextUtil.ts diff --git a/extensions/php/src/features/validationProvider.ts b/extensions/php-language-features/src/features/validationProvider.ts similarity index 100% rename from extensions/php/src/features/validationProvider.ts rename to extensions/php-language-features/src/features/validationProvider.ts diff --git a/extensions/php/src/phpMain.ts b/extensions/php-language-features/src/phpMain.ts similarity index 100% rename from extensions/php/src/phpMain.ts rename to extensions/php-language-features/src/phpMain.ts diff --git a/extensions/php/src/test/index.ts b/extensions/php-language-features/src/test/index.ts similarity index 100% rename from extensions/php/src/test/index.ts rename to extensions/php-language-features/src/test/index.ts diff --git a/extensions/php/src/test/php-worker.test.ts.disabled b/extensions/php-language-features/src/test/php-worker.test.ts.disabled similarity index 100% rename from extensions/php/src/test/php-worker.test.ts.disabled rename to extensions/php-language-features/src/test/php-worker.test.ts.disabled diff --git a/extensions/php/src/typings/node.additions.d.ts b/extensions/php-language-features/src/typings/node.additions.d.ts similarity index 100% rename from extensions/php/src/typings/node.additions.d.ts rename to extensions/php-language-features/src/typings/node.additions.d.ts diff --git a/extensions/php/src/typings/refs.d.ts b/extensions/php-language-features/src/typings/refs.d.ts similarity index 100% rename from extensions/php/src/typings/refs.d.ts rename to extensions/php-language-features/src/typings/refs.d.ts diff --git a/extensions/php/tsconfig.json b/extensions/php-language-features/tsconfig.json similarity index 100% rename from extensions/php/tsconfig.json rename to extensions/php-language-features/tsconfig.json diff --git a/extensions/php/yarn.lock b/extensions/php-language-features/yarn.lock similarity index 100% rename from extensions/php/yarn.lock rename to extensions/php-language-features/yarn.lock diff --git a/extensions/php/package.json b/extensions/php/package.json index 1a16ec69d5b..64b788d2010 100644 --- a/extensions/php/package.json +++ b/extensions/php/package.json @@ -4,17 +4,9 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "icon": "icons/logo.png", "engines": { "vscode": "0.10.x" }, - "activationEvents": [ - "onLanguage:php" - ], - "main": "./out/phpMain", - "dependencies": { - "vscode-nls": "^3.2.1" - }, "contributes": { "languages": [ { @@ -63,69 +55,9 @@ "language": "php", "path": "./snippets/php.snippets.json" } - ], - "configuration": { - "title": "%configuration.title%", - "type": "object", - "order": 20, - "properties": { - "php.suggest.basic": { - "type": "boolean", - "default": true, - "description": "%configuration.suggest.basic%" - }, - "php.validate.enable": { - "type": "boolean", - "default": true, - "description": "%configuration.validate.enable%" - }, - "php.validate.executablePath": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "%configuration.validate.executablePath%" - }, - "php.validate.run": { - "type": "string", - "enum": [ - "onSave", - "onType" - ], - "default": "onSave", - "description": "%configuration.validate.run%" - } - } - }, - "jsonValidation": [ - { - "fileMatch": "composer.json", - "url": "https://getcomposer.org/schema.json" - } - ], - "commands": [ - { - "title": "%command.untrustValidationExecutable%", - "category": "%commands.categroy.php%", - "command": "php.untrustValidationExecutable" - } - ], - "menus": { - "commandPalette": [ - { - "command": "php.untrustValidationExecutable", - "when": "php.untrustValidationExecutableContext" - } - ] - } + ] }, "scripts": { - "compile": "gulp compile-extension:php", - "watch": "gulp watch-extension:php", "update-grammar": "node ./build/update-grammar.js" - }, - "devDependencies": { - "@types/node": "7.0.43" } } diff --git a/extensions/php/package.nls.json b/extensions/php/package.nls.json index 89a9cfedd29..b6170bf3b9a 100644 --- a/extensions/php/package.nls.json +++ b/extensions/php/package.nls.json @@ -1,11 +1,4 @@ { - "configuration.suggest.basic": "Configures if the built-in PHP language suggestions are enabled. The support suggests PHP globals and variables.", - "configuration.validate.enable": "Enable/disable built-in PHP validation.", - "configuration.validate.executablePath": "Points to the PHP executable.", - "configuration.validate.run": "Whether the linter is run on save or on type.", - "configuration.title": "PHP", - "commands.categroy.php": "PHP", - "command.untrustValidationExecutable": "Disallow PHP validation executable (defined as workspace setting)", "displayName": "PHP Language Features", - "description": "Provides IntelliSense, linting, and language basics for PHP files." + "description": "Provides syntax highlighting and bracket matching for PHP files." } \ No newline at end of file diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 25d88261148..3c29932bdee 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -312,7 +312,7 @@ "editorHoverWidget.background": "#000c38", "editorHoverWidget.border": "#004c18", "editorLineNumber.foreground": "#406385", - "editorActiveLineNumber.foreground": "#80a2c2", + "editorLineNumber.activeForeground": "#80a2c2", "editorMarkerNavigation.background": "#060621", "editorMarkerNavigationError.background": "#AB395B", "editorMarkerNavigationWarning.background": "#5B7E7A", diff --git a/extensions/theme-defaults/themes/light_defaults.json b/extensions/theme-defaults/themes/light_defaults.json index d11b218b290..4e50029e23c 100644 --- a/extensions/theme-defaults/themes/light_defaults.json +++ b/extensions/theme-defaults/themes/light_defaults.json @@ -10,6 +10,7 @@ "editorSuggestWidget.background": "#F3F3F3", "activityBarBadge.background": "#007ACC", "sideBarTitle.foreground": "#6F6F6F", - "list.hoverBackground": "#E8E8E8" + "list.hoverBackground": "#E8E8E8", + "input.placeholderForeground": "#ADADAD" } } \ No newline at end of file diff --git a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json index d9c98d09157..ebcf0341dc8 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -20,7 +20,7 @@ "editorHoverWidget.background": "#221a14", "editorGroupHeader.tabsBackground": "#131510", "editorGroup.background": "#0f0c08", - "editorActiveLineNumber.foreground": "#adadad", + "editorLineNumber.activeForeground": "#adadad", "tab.inactiveBackground": "#131510", "titleBar.activeBackground": "#423523", "statusBar.background": "#423523", diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index 1ac4adbc7f4..0a45c9ffe88 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -13,7 +13,7 @@ "editor.selectionBackground": "#676b7180", "editor.selectionHighlightBackground": "#575b6180", "editor.lineHighlightBackground": "#303030", - "editorActiveLineNumber.foreground": "#949494", + "editorLineNumber.activeForeground": "#949494", "editor.wordHighlightBackground": "#4747a180", "editor.wordHighlightStrongBackground": "#6767ce80", "editorCursor.foreground": "#c07020", diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index 208b6b39538..610bf0dc5a2 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -12,7 +12,7 @@ "list.focusBackground": "#414339", "dropdown.listBackground": "#1e1f1c", "list.inactiveSelectionBackground": "#414339", - "list.hoverBackground": "#272822", + "list.hoverBackground": "#3e3d32", "list.dropBackground": "#414339", "list.highlightForeground": "#f8f8f2", "button.background": "#75715E", @@ -24,7 +24,7 @@ "editor.wordHighlightBackground": "#4a4a7680", "editor.wordHighlightStrongBackground": "#6a6a9680", "editor.lineHighlightBackground": "#3e3d32", - "editorActiveLineNumber.foreground": "#c2c2bf", + "editorLineNumber.activeForeground": "#c2c2bf", "editorCursor.foreground": "#f8f8f0", "editorWhitespace.foreground": "#464741", "editorIndentGuide.background": "#464741", diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 9a947168714..3e1ad56f8ad 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -494,7 +494,7 @@ "editor.background": "#F5F5F5", "editorWhitespace.foreground": "#AAAAAA", "editor.lineHighlightBackground": "#E4F6D4", - "editorActiveLineNumber.foreground": "#9769dc", + "editorLineNumber.activeForeground": "#9769dc", "editor.selectionBackground": "#C9D0D9", "panel.background": "#F5F5F5", "sideBar.background": "#F2F2F2", diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 43eaa9b6414..8d69156514c 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -21,7 +21,7 @@ "editorWhitespace.foreground": "#c10000", "editor.selectionBackground": "#750000", "editorLineNumber.foreground": "#ff777788", - "editorActiveLineNumber.foreground": "#ffbbbb88", + "editorLineNumber.activeForeground": "#ffbbbb88", "editorWidget.background": "#300000", "editorHoverWidget.background": "#300000", "editorSuggestWidget.background": "#300000", diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index e0c5df0f187..2f5db67fbad 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -355,7 +355,7 @@ "editorCursor.foreground": "#D30102", "editorWhitespace.foreground": "#93A1A180", "editor.lineHighlightBackground": "#073642", - "editorActiveLineNumber.foreground": "#949494", + "editorLineNumber.activeForeground": "#949494", "editor.selectionBackground": "#073642", // "editorIndentGuide.background": "", "editorHoverWidget.background": "#004052", diff --git a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json index 0d5b202ea12..d752a613c38 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -354,7 +354,7 @@ "editor.selectionBackground": "#EEE8D5", // "editorIndentGuide.background": "", "editorHoverWidget.background": "#CCC4B0", - "editorActiveLineNumber.foreground": "#567983", + "editorLineNumber.activeForeground": "#567983", // "editorHoverWidget.border": "", // "editorLineNumber.foreground": "", // "editorMarkerNavigation.background": "", diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json index 0b89e5b9e6c..de15bf88bc8 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json @@ -15,7 +15,7 @@ "editor.foreground": "#ffffff", "editor.selectionBackground": "#003f8e", "editor.lineHighlightBackground": "#00346e", - "editorActiveLineNumber.foreground": "#949494", + "editorLineNumber.activeForeground": "#949494", "editorCursor.foreground": "#ffffff", "editorWhitespace.foreground": "#404f7d", "editorWidget.background": "#001c40", diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index fceb22b17de..691ad1631b6 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -46,7 +46,8 @@ "tokenTypes": { "entity.name.type.instance.jsdoc": "other", "entity.name.function.tagged-template.ts": "other", - "entity.name.function.tagged-template.tsx": "other" + "entity.name.function.tagged-template.tsx": "other", + "meta.import string.quoted": "other" } }, { @@ -62,7 +63,8 @@ "tokenTypes": { "entity.name.type.instance.jsdoc": "other", "entity.name.function.tagged-template.ts": "other", - "entity.name.function.tagged-template.tsx": "other" + "entity.name.function.tagged-template.tsx": "other", + "meta.import string.quoted": "other" } } ], diff --git a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json index 21fba6f0e64..723570e8d51 100644 --- a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4ef3570784b60450d6baac681cb096fbf1d2397e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/e375f754b1e6d35133b933131121c634ff6a0aeb", "name": "TypeScript", "scopeName": "source.ts", "patterns": [ @@ -1638,6 +1638,26 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "begin": "(?<=^import|[^\\._$[:alnum:]]import)(?!\\s*[\"'])", + "end": "\\bfrom\\b", + "endCaptures": { + "0": { + "name": "keyword.control.from.ts" + } + }, + "patterns": [ + { + "include": "#import-export-declaration" + } + ] + }, { "include": "#import-export-declaration" } @@ -1920,7 +1940,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.ts", - "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.ts", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2209,7 +2229,7 @@ "patterns": [ { "name": "cast.expr.ts", - "begin": "(?:(?<=^return|[^\\._$[:alnum:]]return|^throw|[^\\._$[:alnum:]]throw|^yield|[^\\._$[:alnum:]]yield|^await|[^\\._$[:alnum:]]await|^default|[^\\._$[:alnum:]]default|[=(,:>*?\\&\\|\\^]|[^_$[:alnum:]](?:\\+\\+|\\-\\-)|[^\\+]\\+|[^\\-]\\-))\\s*(<)(?!*?\\&\\|\\^]|[^_$[:alnum:]](?:\\+\\+|\\-\\-)|[^\\+]\\+|[^\\-]\\-))\\s*(<)(?!|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.ts" } }, - "end": "(/)([gimuy]*)", + "end": "(/)([gimsuy]*)", "endCaptures": { "1": { "name": "punctuation.definition.string.end.ts" @@ -3463,13 +3487,13 @@ }, { "name": "string.regexp.ts", - "begin": "(?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } }, { "name": "keyword.operator.quantifier.regexp", @@ -3506,7 +3537,7 @@ }, { "name": "meta.group.assertion.regexp", - "begin": "(\\()((\\?=)|(\\?!))", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", "beginCaptures": { "0": { "name": "punctuation.definition.group.regexp" }, "1": { "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" } }, "end": "\\)", diff --git a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json index 7850f85f533..a230668f744 100644 --- a/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4ef3570784b60450d6baac681cb096fbf1d2397e", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/e375f754b1e6d35133b933131121c634ff6a0aeb", "name": "TypeScriptReact", "scopeName": "source.tsx", "patterns": [ @@ -1641,6 +1641,26 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "begin": "(?<=^import|[^\\._$[:alnum:]]import)(?!\\s*[\"'])", + "end": "\\bfrom\\b", + "endCaptures": { + "0": { + "name": "keyword.control.from.tsx" + } + }, + "patterns": [ + { + "include": "#import-export-declaration" + } + ] + }, { "include": "#import-export-declaration" } @@ -1923,7 +1943,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.tsx", - "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.tsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2495,12 +2515,16 @@ }, { "name": "support.class.builtin.tsx", - "match": "(?x)(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.tsx" } }, - "end": "(/)([gimuy]*)", + "end": "(/)([gimsuy]*)", "endCaptures": { "1": { "name": "punctuation.definition.string.end.tsx" @@ -3429,13 +3453,13 @@ }, { "name": "string.regexp.tsx", - "begin": "(?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } }, { "name": "keyword.operator.quantifier.regexp", @@ -3472,7 +3503,7 @@ }, { "name": "meta.group.assertion.regexp", - "begin": "(\\()((\\?=)|(\\?!))", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", "beginCaptures": { "0": { "name": "punctuation.definition.group.regexp" }, "1": { "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" } }, "end": "\\)", @@ -4152,7 +4192,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?))", "patterns": [ { @@ -4212,8 +4252,8 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", - "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", "patterns": [ { "include": "#jsx-tag" @@ -4222,7 +4262,7 @@ }, "jsx-tag": { "name": "meta.tag.tsx", - "begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", + "begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>))", "end": "(/>)|(?:())", "endCaptures": { "1": { @@ -4249,7 +4289,7 @@ }, "patterns": [ { - "begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>)", + "begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,]|=>|&(?!&)|\\|(?!\\|)))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>)?\\s+(?!\\?)|\\/?>)", "beginCaptures": { "1": { "name": "punctuation.definition.tag.begin.tsx" @@ -4358,6 +4398,9 @@ "begin": "\\s+", "end": "(?=[/]?>)", "patterns": [ + { + "include": "#comment" + }, { "include": "#jsx-tag-attribute-name" }, diff --git a/extensions/typescript/.vscodeignore b/extensions/typescript-language-features/.vscodeignore similarity index 100% rename from extensions/typescript/.vscodeignore rename to extensions/typescript-language-features/.vscodeignore diff --git a/extensions/typescript/OSSREADME.json b/extensions/typescript-language-features/OSSREADME.json similarity index 100% rename from extensions/typescript/OSSREADME.json rename to extensions/typescript-language-features/OSSREADME.json diff --git a/extensions/typescript/icon.png b/extensions/typescript-language-features/icon.png similarity index 100% rename from extensions/typescript/icon.png rename to extensions/typescript-language-features/icon.png diff --git a/extensions/typescript/language-configuration.json b/extensions/typescript-language-features/language-configuration.json similarity index 100% rename from extensions/typescript/language-configuration.json rename to extensions/typescript-language-features/language-configuration.json diff --git a/extensions/typescript/package.json b/extensions/typescript-language-features/package.json similarity index 86% rename from extensions/typescript/package.json rename to extensions/typescript-language-features/package.json index efac422b8ad..e4b92c6fa46 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript-language-features/package.json @@ -36,6 +36,7 @@ "onCommand:javascript.goToProjectConfig", "onCommand:typescript.goToProjectConfig", "onCommand:typescript.openTsServerLog", + "onCommand:typescript.organizeImports", "onCommand:workbench.action.tasks.runTask" ], "main": "./out/extension", @@ -106,6 +107,17 @@ "description": "%typescript.tsserver.log%", "scope": "window" }, + "typescript.tsserver.pluginPaths": { + "type": "array", + "items": { + "type": "string", + "description": "%typescript.tsserver.pluginPaths.item%" + }, + "default": [], + "description": "%typescript.tsserver.pluginPaths%", + "scope": "window", + "isExecutable": true + }, "typescript.tsserver.trace": { "type": "string", "enum": [ @@ -399,67 +411,75 @@ }, "typescript.experimental.syntaxFolding": { "type": "boolean", - "default": false, + "default": true, "description": "%typescript.experimental.syntaxFolding%" + }, + "javascript.suggestionActions.enabled": { + "type": "boolean", + "default": true, + "description": "%javascript.suggestionActions.enabled%", + "scope": "window" + }, + "typescript.suggestionActions.enabled": { + "type": "boolean", + "default": true, + "description": "%typescript.suggestionActions.enabled%", + "scope": "window" } } }, "commands": [ { "command": "typescript.reloadProjects", - "title": { - "original": "Reload Project", - "value": "%typescript.reloadProjects.title%" - }, + "title": "%typescript.reloadProjects.title%", "category": "TypeScript" }, { "command": "javascript.reloadProjects", - "title": { - "original": "Reload Project", - "value": "%javascript.reloadProjects.title%" - }, + "title": "%javascript.reloadProjects.title%", "category": "JavaScript" }, { "command": "typescript.selectTypeScriptVersion", - "title": { - "original": "Select TypeScript Version", - "value": "%typescript.selectTypeScriptVersion.title%" - }, + "title": "%typescript.selectTypeScriptVersion.title%", "category": "TypeScript" }, { "command": "typescript.goToProjectConfig", - "title": { - "original": "Go to Project Configuration", - "value": "%typescript.goToProjectConfig.title%" - }, + "title": "%typescript.goToProjectConfig.title%", "category": "TypeScript" }, { "command": "javascript.goToProjectConfig", - "title": { - "original": "Go to Project Configuration", - "value": "%javascript.goToProjectConfig.title%" - }, + "title": "%javascript.goToProjectConfig.title%", "category": "JavaScript" }, { "command": "typescript.openTsServerLog", - "title": { - "original": "Open TS Server log", - "value": "%typescript.openTsServerLog.title%" - }, + "title": "%typescript.openTsServerLog.title%", "category": "TypeScript" }, { "command": "typescript.restartTsServer", - "title": { - "original": "Restart TS server", - "value": "%typescript.restartTsServer%" - }, + "title": "%typescript.restartTsServer%", "category": "TypeScript" + }, + { + "command": "typescript.organizeImports", + "title": "%typescript.organizeImports%", + "category": "TypeScript" + }, + { + "command": "javascript.organizeImports", + "title": "%typescript.organizeImports%", + "category": "JavaScript" + } + ], + "keybindings": [ + { + "command": "typescript.organizeImports", + "key": "shift+alt+o", + "when": "typescript.isManagedFile && typescript.canOrganizeImports" } ], "menus": { @@ -507,6 +527,22 @@ { "command": "typescript.restartTsServer", "when": "typescript.isManagedFile" + }, + { + "command": "typescript.organizeImports", + "when": "editorLangId == typescriptreact && typescript.isManagedFile && typescript.canOrganizeImports" + }, + { + "command": "typescript.organizeImports", + "when": "editorLangId == typescript && typescript.isManagedFile && typescript.canOrganizeImports" + }, + { + "command": "javascript.organizeImports", + "when": "editorLangId == javascriptreact && typescript.isManagedFile && typescript.canOrganizeImports" + }, + { + "command": "javascript.organizeImports", + "when": "editorLangId == javascript && typescript.isManagedFile && typescript.canOrganizeImports" } ] }, @@ -518,7 +554,6 @@ "language": "typescriptreact" } ], - "taskDefinitions": [ { "type": "typescript", @@ -574,10 +609,10 @@ "background": { "activeOnStart": true, "beginsPattern": { - "regexp": "^\\s*(?:message TS6032:|\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? -) File change detected\\. Starting incremental compilation\\.\\.\\." + "regexp": "^\\s*(?:message TS6032:|\\[?\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM| a\\.m\\.| p\\.m\\.)?(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\." }, "endsPattern": { - "regexp": "^\\s*(?:message TS6042:|\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? -) Compilation complete\\. Watching for file changes\\." + "regexp": "^\\s*(?:message TS6042:|\\[?\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM| a\\.m\\.| p\\.m\\.)?(?:\\]| -)) Compilation complete\\. Watching for file changes\\." } } } diff --git a/extensions/typescript/package.nls.json b/extensions/typescript-language-features/package.nls.json similarity index 90% rename from extensions/typescript/package.nls.json rename to extensions/typescript-language-features/package.nls.json index c8b37dfddd5..a3a7df1f473 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -8,6 +8,8 @@ "typescript.tsdk.desc": "Specifies the folder path containing the tsserver and lib*.d.ts files to use.", "typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Requires TypeScript >= 2.0.6.", "typescript.tsserver.log": "Enables logging of the TS server to a file. This log can be used to diagnose TS Server issues. The log may contain file paths, source code, and other potentially sensitive information from your project.", + "typescript.tsserver.pluginPaths": "Additional paths to discover Typescript Language Service plugins. Requires TypeScript >= 2.3.0.", + "typescript.tsserver.pluginPaths.item": "Either an absolute or relative path. Relative path will be resolved against workspace folder(s).", "typescript.tsserver.trace": "Enables tracing of messages sent to the TS server. This trace can be used to diagnose TS Server issues. The trace may contain file paths, source code, and other potentially sensitive information from your project.", "typescript.validate.enable": "Enable/disable TypeScript validation.", "typescript.format.enable": "Enable/disable default TypeScript formatter.", @@ -50,5 +52,8 @@ "javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable 'experimentalDecorators' for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting. Requires TypeScript >=2.3.1.", "typescript.autoImportSuggestions.enabled": "Enable/disable auto import suggestions. Requires TypeScript >=2.6.1", "typescript.experimental.syntaxFolding": "Enables/disables syntax aware folding markers.", - "taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build." + "taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.", + "typescript.organizeImports": "Organize Imports", + "javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor. Requires TypeScript >= 2.8", + "typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor. Requires TypeScript >= 2.8." } \ No newline at end of file diff --git a/extensions/typescript/src/commands.ts b/extensions/typescript-language-features/src/commands.ts similarity index 100% rename from extensions/typescript/src/commands.ts rename to extensions/typescript-language-features/src/commands.ts diff --git a/extensions/typescript/src/extension.ts b/extensions/typescript-language-features/src/extension.ts similarity index 91% rename from extensions/typescript/src/extension.ts rename to extensions/typescript-language-features/src/extension.ts index 73604a21c3f..ac33918d1c2 100644 --- a/extensions/typescript/src/extension.ts +++ b/extensions/typescript-language-features/src/extension.ts @@ -19,6 +19,7 @@ import ManagedFileContextManager from './utils/managedFileContext'; import { lazy, Lazy } from './utils/lazy'; import * as fileSchemes from './utils/fileSchemes'; import LogDirectoryProvider from './utils/logDirectoryProvider'; +import { OrganizeImportsCommand, OrganizeImportsContextManager } from './features/organizeImports'; export function activate( context: vscode.ExtensionContext @@ -70,7 +71,14 @@ function createLazyClientHost( plugins, commandManager, logDirectoryProvider); + context.subscriptions.push(clientHost); + + const organizeImportsContext = new OrganizeImportsContextManager(); + clientHost.serviceClient.onTsServerStarted(api => { + organizeImportsContext.onDidChangeApiVersion(api); + }, null, context.subscriptions); + clientHost.serviceClient.onReady(() => { context.subscriptions.push( ProjectStatus.create( @@ -79,6 +87,7 @@ function createLazyClientHost( path => new Promise(resolve => setTimeout(() => resolve(clientHost.handles(path)), 750)), context.workspaceState)); }); + return clientHost; }); } @@ -94,6 +103,7 @@ function registerCommands( commandManager.register(new commands.RestartTsServerCommand(lazyClientHost)); commandManager.register(new commands.TypeScriptGoToProjectConfigCommand(lazyClientHost)); commandManager.register(new commands.JavaScriptGoToProjectConfigCommand(lazyClientHost)); + commandManager.register(new OrganizeImportsCommand(lazyClientHost)); } function isSupportedDocument( diff --git a/extensions/typescript/src/features/baseCodeLensProvider.ts b/extensions/typescript-language-features/src/features/baseCodeLensProvider.ts similarity index 97% rename from extensions/typescript/src/features/baseCodeLensProvider.ts rename to extensions/typescript-language-features/src/features/baseCodeLensProvider.ts index 427118b68ef..019130f04f9 100644 --- a/extensions/typescript/src/features/baseCodeLensProvider.ts +++ b/extensions/typescript-language-features/src/features/baseCodeLensProvider.ts @@ -7,7 +7,7 @@ import { CodeLensProvider, CodeLens, CancellationToken, TextDocument, Range, Uri import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import { escapeRegExp } from '../utils/regexp'; export class ReferencesCodeLens extends CodeLens { @@ -136,7 +136,7 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider return null; } - const range = tsTextSpanToVsRange(span); + const range = typeConverters.Range.fromTextSpan(span); const text = document.getText(range); const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${escapeRegExp(item.text || '')}(\\b|\\W)`, 'gm'); diff --git a/extensions/typescript/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts similarity index 95% rename from extensions/typescript/src/features/bufferSyncSupport.ts rename to extensions/typescript-language-features/src/features/bufferSyncSupport.ts index ff4ccde6ec6..105663f14e4 100644 --- a/extensions/typescript/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -153,7 +153,7 @@ export default class BufferSyncSupport { private readonly disposables: Disposable[] = []; private readonly syncedBuffers: SyncedBufferMap; - private pendingDiagnostics = new Map(); + private readonly pendingDiagnostics = new Map(); private readonly diagnosticDelayer: Delayer; constructor( @@ -267,20 +267,18 @@ export default class BufferSyncSupport { }, delay); } + public hasPendingDiagnostics(resource: Uri): boolean { + const file = this.client.normalizePath(resource); + return !file || this.pendingDiagnostics.has(file); + } + private sendPendingDiagnostics(): void { if (!this._validate) { return; } - let files = Array.from(this.pendingDiagnostics.entries()).map(([key, value]) => { - return { - file: key, - time: value - }; - }).sort((a, b) => { - return a.time - b.time; - }).map((value) => { - return value.file; - }); + const files = Array.from(this.pendingDiagnostics.entries()) + .sort((a, b) => a[1] - b[1]) + .map(entry => entry[0]); // Add all open TS buffers to the geterr request. They might be visible for (const file of this.syncedBuffers.allResources) { diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript-language-features/src/features/completionItemProvider.ts similarity index 88% rename from extensions/typescript/src/features/completionItemProvider.ts rename to extensions/typescript-language-features/src/features/completionItemProvider.ts index 3bb74175105..2a2c58cab04 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript-language-features/src/features/completionItemProvider.ts @@ -11,11 +11,10 @@ import TypingsStatus from '../utils/typingsStatus'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import * as Previewer from '../utils/previewer'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import * as nls from 'vscode-nls'; import { applyCodeAction } from '../utils/codeAction'; -import * as languageModeIds from '../utils/languageModeIds'; import { CommandManager, Command } from '../utils/commandManager'; const localize = nls.loadMessageBundle(); @@ -51,14 +50,14 @@ class MyCompletionItem extends vscode.CompletionItem { this.useCodeSnippet = useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method); if (tsEntry.replacementSpan) { - this.range = tsTextSpanToVsRange(tsEntry.replacementSpan); + this.range = typeConverters.Range.fromTextSpan(tsEntry.replacementSpan); } if (tsEntry.insertText) { this.insertText = tsEntry.insertText; if (tsEntry.replacementSpan) { - this.range = tsTextSpanToVsRange(tsEntry.replacementSpan); + this.range = typeConverters.Range.fromTextSpan(tsEntry.replacementSpan); if (this.insertText[0] === '[') { // o.x -> o['x'] this.filterText = '.' + this.label; } @@ -281,7 +280,7 @@ export default class TypeScriptCompletionItemProvider implements vscode.Completi } const args: Proto.CompletionsRequestArgs = { - ...vsPositionToTsFileLocation(file, position), + ...typeConverters.Position.toFileLocationRequestArgs(file, position), includeExternalModuleExports: completionConfiguration.autoImportSuggestions, includeInsertTextCompletions: true }; @@ -330,7 +329,7 @@ export default class TypeScriptCompletionItemProvider implements vscode.Completi item.resolve(); const args: Proto.CompletionDetailsRequestArgs = { - ...vsPositionToTsFileLocation(filepath, item.position), + ...typeConverters.Position.toFileLocationRequestArgs(filepath, item.position), entryNames: [ item.tsEntry.source ? { name: item.tsEntry.name, source: item.tsEntry.source } : item.tsEntry.name ] @@ -351,34 +350,74 @@ export default class TypeScriptCompletionItemProvider implements vscode.Completi item.detail = detail.displayParts.length ? Previewer.plain(detail.displayParts) : undefined; item.documentation = this.getDocumentation(detail, item); - if (detail.codeActions && detail.codeActions.length) { - item.command = { - title: '', - command: ApplyCompletionCodeActionCommand.ID, - arguments: [filepath, detail.codeActions] - }; - } + const { command, additionalTextEdits } = this.getCodeActions(detail, filepath); + item.command = command; + item.additionalTextEdits = additionalTextEdits; if (detail && item.useCodeSnippet) { const shouldCompleteFunction = await this.isValidFunctionCompletionContext(filepath, item.position); if (shouldCompleteFunction) { item.insertText = this.snippetForFunctionCall(item, detail); } - return item; } return item; } + private getCodeActions( + detail: Proto.CompletionEntryDetails, + filepath: string + ): { command?: vscode.Command, additionalTextEdits?: vscode.TextEdit[] } { + if (!detail.codeActions || !detail.codeActions.length) { + return {}; + } + + // Try to extract out the additionalTextEdits for the current file. + // Also check if we still have to apply other workspace edits and commands + // using a vscode command + const additionalTextEdits: vscode.TextEdit[] = []; + let hasReaminingCommandsOrEdits = false; + for (const tsAction of detail.codeActions) { + if (tsAction.commands) { + hasReaminingCommandsOrEdits = true; + } + + // Apply all edits in the current file using `additionalTextEdits` + if (tsAction.changes) { + for (const change of tsAction.changes) { + if (change.fileName === filepath) { + additionalTextEdits.push(...change.textChanges.map(typeConverters.TextEdit.fromCodeEdit)); + } else { + hasReaminingCommandsOrEdits = true; + } + } + } + } + + let command: vscode.Command | undefined = undefined; + if (hasReaminingCommandsOrEdits) { + // Create command that applies all edits not in the current file. + command = { + title: '', + command: ApplyCompletionCodeActionCommand.ID, + arguments: [filepath, detail.codeActions.map((x): Proto.CodeAction => ({ + commands: x.commands, + description: x.description, + changes: x.changes.filter(x => x.fileName !== filepath) + }))] + }; + } + + return { + command, + additionalTextEdits: additionalTextEdits.length ? additionalTextEdits : undefined + }; + } + private shouldEnableDotCompletions( document: vscode.TextDocument, position: vscode.Position ): boolean { - // Only enable dot completions in TS files for now - if (document.languageId !== languageModeIds.typescript && document.languageId === languageModeIds.typescriptreact) { - return false; - } - // TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/13456 // Only enable dot completions when previous character is an identifier. // Prevents incorrectly completing while typing spread operators. @@ -455,7 +494,7 @@ export default class TypeScriptCompletionItemProvider implements vscode.Completi // Workaround for https://github.com/Microsoft/TypeScript/issues/12677 // Don't complete function calls inside of destructive assigments or imports try { - const infoResponse = await this.client.execute('quickinfo', vsPositionToTsFileLocation(filepath, position)); + const infoResponse = await this.client.execute('quickinfo', typeConverters.Position.toFileLocationRequestArgs(filepath, position)); const info = infoResponse.body; switch (info && info.kind) { case 'var': diff --git a/extensions/typescript/src/features/definitionProvider.ts b/extensions/typescript-language-features/src/features/definitionProvider.ts similarity index 100% rename from extensions/typescript/src/features/definitionProvider.ts rename to extensions/typescript-language-features/src/features/definitionProvider.ts diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript-language-features/src/features/definitionProviderBase.ts similarity index 70% rename from extensions/typescript/src/features/definitionProviderBase.ts rename to extensions/typescript-language-features/src/features/definitionProviderBase.ts index a931905bb4d..f8928579e07 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript-language-features/src/features/definitionProviderBase.ts @@ -7,11 +7,11 @@ import { TextDocument, Position, CancellationToken, Location } from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; export default class TypeScriptDefinitionProviderBase { constructor( - private client: ITypeScriptServiceClient + private readonly client: ITypeScriptServiceClient ) { } protected async getSymbolLocations( @@ -25,19 +25,12 @@ export default class TypeScriptDefinitionProviderBase { return undefined; } - const args = vsPositionToTsFileLocation(filepath, position); + const args = typeConverters.Position.toFileLocationRequestArgs(filepath, position); try { const response = await this.client.execute(definitionType, args, token); const locations: Proto.FileSpan[] = (response && response.body) || []; - if (!locations || locations.length === 0) { - return []; - } - return locations.map(location => { - const resource = this.client.asUrl(location.file); - return resource - ? new Location(resource, tsTextSpanToVsRange(location)) - : undefined; - }).filter(x => x) as Location[]; + return locations.map(location => + typeConverters.Location.fromTextSpan(this.client.asUrl(location.file), location)); } catch { return []; } diff --git a/extensions/typescript-language-features/src/features/diagnostics.ts b/extensions/typescript-language-features/src/features/diagnostics.ts new file mode 100644 index 00000000000..1bde0c8353e --- /dev/null +++ b/extensions/typescript-language-features/src/features/diagnostics.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +class DiagnosticSet { + private _map: ObjectMap = Object.create(null); + + public set( + file: vscode.Uri, + diagnostics: vscode.Diagnostic[] + ) { + this._map[this.key(file)] = diagnostics; + } + + public get(file: vscode.Uri): vscode.Diagnostic[] { + return this._map[this.key(file)] || []; + } + + public clear(): void { + this._map = Object.create(null); + } + + private key(file: vscode.Uri): string { + return file.toString(true); + } +} + +export enum DiagnosticKind { + Syntax, + Semantic, + Suggestion +} + +const allDiagnosticKinds = [DiagnosticKind.Syntax, DiagnosticKind.Semantic, DiagnosticKind.Suggestion]; + +export class DiagnosticsManager { + + private readonly _diagnostics = new Map(); + private readonly _currentDiagnostics: vscode.DiagnosticCollection; + private _validate: boolean = true; + private _enableSuggestions: boolean = true; + + constructor( + language: string + ) { + for (const kind of allDiagnosticKinds) { + this._diagnostics.set(kind, new DiagnosticSet()); + } + + this._currentDiagnostics = vscode.languages.createDiagnosticCollection(language); + } + + public dispose() { + this._currentDiagnostics.dispose(); + } + + public reInitialize(): void { + this._currentDiagnostics.clear(); + + for (const diagnosticSet of this._diagnostics.values()) { + diagnosticSet.clear(); + } + } + + public set validate(value: boolean) { + if (this._validate === value) { + return; + } + + this._validate = value; + if (!value) { + this._currentDiagnostics.clear(); + } + } + + public set enableSuggestions(value: boolean) { + if (this._enableSuggestions === value) { + return; + } + + this._enableSuggestions = value; + if (!value) { + this._currentDiagnostics.clear(); + } + } + + public diagnosticsReceived( + kind: DiagnosticKind, + file: vscode.Uri, + syntaxDiagnostics: vscode.Diagnostic[] + ): void { + const diagnostics = this._diagnostics.get(kind); + if (diagnostics) { + diagnostics.set(file, syntaxDiagnostics); + this.updateCurrentDiagnostics(file); + } + } + + public configFileDiagnosticsReceived(file: vscode.Uri, diagnostics: vscode.Diagnostic[]): void { + this._currentDiagnostics.set(file, diagnostics); + } + + public delete(resource: vscode.Uri): void { + this._currentDiagnostics.delete(resource); + } + + private updateCurrentDiagnostics(file: vscode.Uri) { + if (!this._validate) { + return; + } + + const allDiagnostics: vscode.Diagnostic[] = []; + allDiagnostics.push(...this._diagnostics.get(DiagnosticKind.Syntax)!.get(file)); + allDiagnostics.push(...this._diagnostics.get(DiagnosticKind.Semantic)!.get(file)); + if (this._enableSuggestions) { + allDiagnostics.push(...this._diagnostics.get(DiagnosticKind.Suggestion)!.get(file)); + } + this._currentDiagnostics.set(file, allDiagnostics); + } + + public getDiagnostics(file: vscode.Uri): vscode.Diagnostic[] { + return this._currentDiagnostics.get(file) || []; + } +} \ No newline at end of file diff --git a/extensions/typescript/src/features/directiveCommentCompletionProvider.ts b/extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts similarity index 97% rename from extensions/typescript/src/features/directiveCommentCompletionProvider.ts rename to extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts index 60ae5cf14c0..928c5005ffa 100644 --- a/extensions/typescript/src/features/directiveCommentCompletionProvider.ts +++ b/extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts @@ -36,7 +36,7 @@ const directives: Directive[] = [ export default class DirectiveCommentCompletionProvider implements CompletionItemProvider { constructor( - private client: ITypeScriptServiceClient, + private readonly client: ITypeScriptServiceClient, ) { } public provideCompletionItems( diff --git a/extensions/typescript-language-features/src/features/documentHighlightProvider.ts b/extensions/typescript-language-features/src/features/documentHighlightProvider.ts new file mode 100644 index 00000000000..15c9f0c8c5b --- /dev/null +++ b/extensions/typescript-language-features/src/features/documentHighlightProvider.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DocumentHighlightProvider, DocumentHighlight, DocumentHighlightKind, TextDocument, Position, CancellationToken } from 'vscode'; + +import * as Proto from '../protocol'; + +import { ITypeScriptServiceClient } from '../typescriptService'; +import * as typeConverters from '../utils/typeConverters'; + +export default class TypeScriptDocumentHighlightProvider implements DocumentHighlightProvider { + public constructor( + private readonly client: ITypeScriptServiceClient + ) { } + + public async provideDocumentHighlights( + resource: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + const file = this.client.normalizePath(resource.uri); + if (!file) { + return []; + } + + const args = typeConverters.Position.toFileLocationRequestArgs(file, position); + try { + const response = await this.client.execute('occurrences', args, token); + if (response && response.body) { + return response.body + .filter(x => !x.isInString) + .map(documentHighlightFromOccurance); + } + } catch { + // noop + } + + return []; + } +} + +function documentHighlightFromOccurance(occurrence: Proto.OccurrencesResponseItem): DocumentHighlight { + return new DocumentHighlight( + typeConverters.Range.fromTextSpan(occurrence), + occurrence.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read); +} \ No newline at end of file diff --git a/extensions/typescript/src/features/documentSymbolProvider.ts b/extensions/typescript-language-features/src/features/documentSymbolProvider.ts similarity index 93% rename from extensions/typescript/src/features/documentSymbolProvider.ts rename to extensions/typescript-language-features/src/features/documentSymbolProvider.ts index c910b5381c0..c71280bfcb8 100644 --- a/extensions/typescript/src/features/documentSymbolProvider.ts +++ b/extensions/typescript-language-features/src/features/documentSymbolProvider.ts @@ -3,12 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, Location, CancellationToken, Uri } from 'vscode'; +import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, CancellationToken, Uri } from 'vscode'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; const outlineTypeTable: { [kind: string]: SymbolKind } = Object.create(null); outlineTypeTable[PConst.Kind.module] = SymbolKind.Module; @@ -29,7 +29,7 @@ outlineTypeTable[PConst.Kind.localFunction] = SymbolKind.Function; export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolProvider { public constructor( - private client: ITypeScriptServiceClient) { } + private readonly client: ITypeScriptServiceClient) { } public async provideDocumentSymbols(resource: TextDocument, token: CancellationToken): Promise { const filepath = this.client.normalizePath(resource.uri); @@ -71,7 +71,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP let result = new SymbolInformation(item.text, outlineTypeTable[item.kind as string] || SymbolKind.Variable, containerLabel ? containerLabel : '', - new Location(resource, tsTextSpanToVsRange(item.spans[0]))); + typeConverters.Location.fromTextSpan(resource, item.spans[0])); foldingMap[key] = result; bucket.push(result); } @@ -86,7 +86,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP const result = new SymbolInformation(item.text, outlineTypeTable[item.kind as string] || SymbolKind.Variable, containerLabel ? containerLabel : '', - new Location(resource, tsTextSpanToVsRange(item.spans[0])) + typeConverters.Location.fromTextSpan(resource, item.spans[0]) ); if (item.childItems && item.childItems.length > 0) { for (const child of item.childItems) { diff --git a/extensions/typescript/src/features/folderingProvider.ts b/extensions/typescript-language-features/src/features/folderingProvider.ts similarity index 56% rename from extensions/typescript/src/features/folderingProvider.ts rename to extensions/typescript-language-features/src/features/folderingProvider.ts index da2ae82fd4d..6c11adb069b 100644 --- a/extensions/typescript/src/features/folderingProvider.ts +++ b/extensions/typescript-language-features/src/features/folderingProvider.ts @@ -6,28 +6,9 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; +import * as typeConverters from '../utils/typeConverters'; import { ITypeScriptServiceClient } from '../typescriptService'; -// TODO: forward declarations for private TS API. - -interface TextSpan { - start: number; - length: number; -} - -interface OutliningSpan { - textSpan: TextSpan; - hintSpan: TextSpan; - bannerText: string; - autoCollapse: boolean; -} - -interface OutliningSpansRequestArgs extends Proto.FileRequestArgs { } - -interface OutliningSpansResponse extends Proto.Response { - body?: OutliningSpan[]; -} - export default class TypeScriptFoldingProvider implements vscode.FoldingProvider { public constructor( private readonly client: ITypeScriptServiceClient @@ -35,10 +16,10 @@ export default class TypeScriptFoldingProvider implements vscode.FoldingProvider async provideFoldingRanges( document: vscode.TextDocument, - _: vscode.FoldingContext, + _context: vscode.FoldingContext, token: vscode.CancellationToken ): Promise { - if (!this.client.apiVersion.has270Features()) { + if (!this.client.apiVersion.has280Features()) { return; } @@ -47,17 +28,15 @@ export default class TypeScriptFoldingProvider implements vscode.FoldingProvider return; } - const args: OutliningSpansRequestArgs = { file }; - const response: OutliningSpansResponse = await this.client.execute('outliningSpans', args, token); + const args: Proto.FileRequestArgs = { file }; + const response: Proto.OutliningSpansResponse = await this.client.execute('getOutliningSpans', args, token); if (!response || !response.body) { return; } return new vscode.FoldingRangeList(response.body.map(span => { - const start = document.positionAt(span.textSpan.start); - const end = document.positionAt(span.textSpan.start + span.textSpan.length); - - return new vscode.FoldingRange(start.line, end.line); + const range = typeConverters.Range.fromTextSpan(span.textSpan); + return new vscode.FoldingRange(range.start.line, range.end.line); })); } -} \ No newline at end of file +} diff --git a/extensions/typescript/src/features/formattingConfigurationManager.ts b/extensions/typescript-language-features/src/features/formattingConfigurationManager.ts similarity index 99% rename from extensions/typescript/src/features/formattingConfigurationManager.ts rename to extensions/typescript-language-features/src/features/formattingConfigurationManager.ts index 09d4a5bdc82..1026eec9a3b 100644 --- a/extensions/typescript/src/features/formattingConfigurationManager.ts +++ b/extensions/typescript-language-features/src/features/formattingConfigurationManager.ts @@ -27,7 +27,7 @@ export default class FormattingConfigurationManager { private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); public constructor( - private client: ITypeScriptServiceClient + private readonly client: ITypeScriptServiceClient ) { this.onDidCloseTextDocumentSub = Workspace.onDidCloseTextDocument((textDocument) => { const key = textDocument.uri.toString(); diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript-language-features/src/features/formattingProvider.ts similarity index 93% rename from extensions/typescript/src/features/formattingProvider.ts rename to extensions/typescript-language-features/src/features/formattingProvider.ts index e65d8ea49c9..d998b95e372 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript-language-features/src/features/formattingProvider.ts @@ -7,7 +7,7 @@ import { DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, Form import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import FormattingConfigurationManager from './formattingConfigurationManager'; export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { @@ -36,7 +36,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit try { const response = await this.client.execute('format', args, token); if (response.body) { - return response.body.map(this.codeEdit2SingleEditOperation); + return response.body.map(typeConverters.TextEdit.fromCodeEdit); } } catch { // noop @@ -92,7 +92,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit return result; } for (const edit of edits) { - const textEdit = this.codeEdit2SingleEditOperation(edit); + const textEdit = typeConverters.TextEdit.fromCodeEdit(edit); const range = textEdit.range; // Work around for https://github.com/Microsoft/TypeScript/issues/6700. // Check if we have an edit at the beginning of the line which only removes white spaces and leaves @@ -114,10 +114,6 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit } return []; } - - private codeEdit2SingleEditOperation(edit: Proto.CodeEdit): TextEdit { - return new TextEdit(tsTextSpanToVsRange(edit), edit.newText); - } } export class FormattingProviderManager { diff --git a/extensions/typescript/src/features/hoverProvider.ts b/extensions/typescript-language-features/src/features/hoverProvider.ts similarity index 86% rename from extensions/typescript/src/features/hoverProvider.ts rename to extensions/typescript-language-features/src/features/hoverProvider.ts index 0a3a99c8ef3..84f54c1b18e 100644 --- a/extensions/typescript/src/features/hoverProvider.ts +++ b/extensions/typescript-language-features/src/features/hoverProvider.ts @@ -8,12 +8,12 @@ import { HoverProvider, Hover, TextDocument, Position, CancellationToken } from import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import { tagsMarkdownPreview } from '../utils/previewer'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; export default class TypeScriptHoverProvider implements HoverProvider { public constructor( - private client: ITypeScriptServiceClient + private readonly client: ITypeScriptServiceClient ) { } public async provideHover( @@ -25,14 +25,14 @@ export default class TypeScriptHoverProvider implements HoverProvider { if (!filepath) { return undefined; } - const args = vsPositionToTsFileLocation(filepath, position); + const args = typeConverters.Position.toFileLocationRequestArgs(filepath, position); try { const response = await this.client.execute('quickinfo', args, token); if (response && response.body) { const data = response.body; return new Hover( TypeScriptHoverProvider.getContents(data), - tsTextSpanToVsRange(data)); + typeConverters.Range.fromTextSpan(data)); } } catch (e) { // noop diff --git a/extensions/typescript/src/features/implementationProvider.ts b/extensions/typescript-language-features/src/features/implementationProvider.ts similarity index 100% rename from extensions/typescript/src/features/implementationProvider.ts rename to extensions/typescript-language-features/src/features/implementationProvider.ts diff --git a/extensions/typescript/src/features/implementationsCodeLensProvider.ts b/extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts similarity index 94% rename from extensions/typescript/src/features/implementationsCodeLensProvider.ts rename to extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts index 1d44d15ed58..fdd5e7ceacc 100644 --- a/extensions/typescript/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts @@ -9,7 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, CachedNavTreeResponse } from './baseCodeLensProvider'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -37,7 +37,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip public resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args = vsPositionToTsFileLocation(codeLens.file, codeLens.range.start); + const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); return this.client.execute('implementation', args, token).then(response => { if (!response || !response.body) { throw codeLens; @@ -48,7 +48,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip // Only take first line on implementation: https://github.com/Microsoft/vscode/issues/23924 new Location(this.client.asUrl(reference.file), reference.start.line === reference.end.line - ? tsTextSpanToVsRange(reference) + ? typeConverters.Range.fromTextSpan(reference) : new Range( reference.start.line - 1, reference.start.offset - 1, reference.start.line, 0))) diff --git a/extensions/typescript/src/features/jsDocCompletionProvider.ts b/extensions/typescript-language-features/src/features/jsDocCompletionProvider.ts similarity index 96% rename from extensions/typescript/src/features/jsDocCompletionProvider.ts rename to extensions/typescript-language-features/src/features/jsDocCompletionProvider.ts index 34963657b28..d22c0b2bf47 100644 --- a/extensions/typescript/src/features/jsDocCompletionProvider.ts +++ b/extensions/typescript-language-features/src/features/jsDocCompletionProvider.ts @@ -9,7 +9,7 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import * as Proto from '../protocol'; import * as nls from 'vscode-nls'; -import { vsPositionToTsFileLocation, tsTextSpanToVsRange } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import { Command, CommandManager } from '../utils/commandManager'; const localize = nls.loadMessageBundle(); @@ -49,7 +49,7 @@ class JsDocCompletionItem extends CompletionItem { export default class JsDocCompletionProvider implements CompletionItemProvider { constructor( - private client: ITypeScriptServiceClient, + private readonly client: ITypeScriptServiceClient, commandManager: CommandManager ) { commandManager.register(new TryCompleteJsDocCommand(client)); @@ -96,7 +96,7 @@ export default class JsDocCompletionProvider implements CompletionItemProvider { if (!tree.spans.length) { return false; } - const span = tsTextSpanToVsRange(tree.spans[0]); + const span = typeConverters.Range.fromTextSpan(tree.spans[0]); if (position.line === span.start.line - 1 || position.line === span.start.line) { return true; } @@ -162,7 +162,7 @@ class TryCompleteJsDocCommand implements Command { } public static getSnippetTemplate(client: ITypeScriptServiceClient, file: string, position: Position): Promise { - const args = vsPositionToTsFileLocation(file, position); + const args = typeConverters.Position.toFileLocationRequestArgs(file, position); return Promise.race([ client.execute('docCommentTemplate', args), new Promise((_, reject) => setTimeout(reject, 250)) diff --git a/extensions/typescript-language-features/src/features/organizeImports.ts b/extensions/typescript-language-features/src/features/organizeImports.ts new file mode 100644 index 00000000000..a92aabc9f9f --- /dev/null +++ b/extensions/typescript-language-features/src/features/organizeImports.ts @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +import * as Proto from '../protocol'; +import { Command } from '../utils/commandManager'; +import * as typeconverts from '../utils/typeConverters'; + +import { isSupportedLanguageMode } from '../utils/languageModeIds'; +import API from '../utils/api'; +import { Lazy } from '../utils/lazy'; +import TypeScriptServiceClientHost from '../typeScriptServiceClientHost'; + +export class OrganizeImportsCommand implements Command { + public static readonly Ids = ['javascript.organizeImports', 'typescript.organizeImports']; + + public readonly id = OrganizeImportsCommand.Ids; + + constructor( + private readonly lazyClientHost: Lazy + ) { } + + public async execute(): Promise { + // Don't force activation + if (!this.lazyClientHost.hasValue) { + return false; + } + + const client = this.lazyClientHost.value.serviceClient; + if (!client.apiVersion.has280Features()) { + return false; + } + + const editor = vscode.window.activeTextEditor; + if (!editor || !isSupportedLanguageMode(editor.document)) { + return false; + } + + const file = client.normalizePath(editor.document.uri); + if (!file) { + return false; + } + + const args: Proto.OrganizeImportsRequestArgs = { + scope: { + type: 'file', + args: { + file + } + } + }; + const response = await client.execute('organizeImports', args); + if (!response || !response.success) { + return false; + } + + const edits = typeconverts.WorkspaceEdit.fromFromFileCodeEdits(client, response.body); + return await vscode.workspace.applyEdit(edits); + } +} + +/** + * When clause context set when the ts version supports organize imports. + */ +const contextName = 'typescript.canOrganizeImports'; + +export class OrganizeImportsContextManager { + + private currentValue: boolean = false; + + public onDidChangeApiVersion(apiVersion: API): any { + this.updateContext(apiVersion.has280Features()); + } + + private updateContext(newValue: boolean) { + if (newValue === this.currentValue) { + return; + } + + vscode.commands.executeCommand('setContext', contextName, newValue); + this.currentValue = newValue; + } +} diff --git a/extensions/typescript/src/features/quickFixProvider.ts b/extensions/typescript-language-features/src/features/quickFixProvider.ts similarity index 93% rename from extensions/typescript/src/features/quickFixProvider.ts rename to extensions/typescript-language-features/src/features/quickFixProvider.ts index 49aaa8b6e04..a85e78e7b6e 100644 --- a/extensions/typescript/src/features/quickFixProvider.ts +++ b/extensions/typescript-language-features/src/features/quickFixProvider.ts @@ -7,12 +7,12 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { vsRangeToTsFileRange } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import FormattingConfigurationManager from './formattingConfigurationManager'; import { getEditForCodeAction, applyCodeActionCommands } from '../utils/codeAction'; import { Command, CommandManager } from '../utils/commandManager'; -import { createWorkspaceEditFromFileCodeEdits } from '../utils/workspaceEdit'; -import DiagnosticsManager from './diagnostics'; +import { DiagnosticsManager } from './diagnostics'; +import BufferSyncSupport from './bufferSyncSupport'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -63,7 +63,7 @@ class ApplyFixAllCodeAction implements Command { return; } - const edit = createWorkspaceEditFromFileCodeEdits(this.client, combinedCodeFixesResponse.body.changes); + const edit = typeConverters.WorkspaceEdit.fromFromFileCodeEdits(this.client, combinedCodeFixesResponse.body.changes); await vscode.workspace.applyEdit(edit); if (combinedCodeFixesResponse.command) { @@ -133,7 +133,9 @@ export default class TypeScriptQuickFixProvider implements vscode.CodeActionProv private readonly client: ITypeScriptServiceClient, private readonly formattingConfigurationManager: FormattingConfigurationManager, commandManager: CommandManager, - private readonly diagnosticsManager: DiagnosticsManager + private readonly diagnosticsManager: DiagnosticsManager, + private readonly bufferSyncSupport: BufferSyncSupport + ) { commandManager.register(new ApplyCodeActionCommand(client)); commandManager.register(new ApplyFixAllCodeAction(client)); @@ -161,6 +163,10 @@ export default class TypeScriptQuickFixProvider implements vscode.CodeActionProv return []; } + if (this.bufferSyncSupport.hasPendingDiagnostics(document.uri)) { + return []; + } + await this.formattingConfigurationManager.ensureFormatOptionsForDocument(document, token); const results: vscode.CodeAction[] = []; @@ -177,7 +183,7 @@ export default class TypeScriptQuickFixProvider implements vscode.CodeActionProv token: vscode.CancellationToken ): Promise> { const args: Proto.CodeFixRequestArgs = { - ...vsRangeToTsFileRange(file, diagnostic.range), + ...typeConverters.Range.toFileRangeRequestArgs(file, diagnostic.range), errorCodes: [+diagnostic.code] }; const codeFixesResponse = await this.client.execute('getCodeFixes', args, token); diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript-language-features/src/features/refactorProvider.ts similarity index 88% rename from extensions/typescript/src/features/refactorProvider.ts rename to extensions/typescript-language-features/src/features/refactorProvider.ts index c6310dcf0d9..17cb2d66f2f 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript-language-features/src/features/refactorProvider.ts @@ -9,7 +9,7 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsRangeToTsFileRange, tsLocationToVsPosition } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import FormattingOptionsManager from './formattingConfigurationManager'; import { CommandManager, Command } from '../utils/commandManager'; @@ -32,7 +32,7 @@ class ApplyRefactoringCommand implements Command { await this.formattingOptionsManager.ensureFormatOptionsForDocument(document, undefined); const args: Proto.GetEditsForRefactorRequestArgs = { - ...vsRangeToTsFileRange(file, range), + ...typeConverters.Range.toFileRangeRequestArgs(file, range), refactor, action }; @@ -41,7 +41,7 @@ class ApplyRefactoringCommand implements Command { return false; } - const edit = this.toWorkspaceEdit(response.body.edits); + const edit = typeConverters.WorkspaceEdit.fromFromFileCodeEdits(this.client, response.body.edits); if (!(await vscode.workspace.applyEdit(edit))) { return false; } @@ -49,25 +49,13 @@ class ApplyRefactoringCommand implements Command { const renameLocation = response.body.renameLocation; if (renameLocation) { if (vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.uri.fsPath === document.uri.fsPath) { - const pos = tsLocationToVsPosition(renameLocation); + const pos = typeConverters.Position.fromLocation(renameLocation); vscode.window.activeTextEditor.selection = new vscode.Selection(pos, pos); await vscode.commands.executeCommand('editor.action.rename'); } } return true; } - - private toWorkspaceEdit(edits: Proto.FileCodeEdits[]): vscode.WorkspaceEdit { - const workspaceEdit = new vscode.WorkspaceEdit(); - for (const edit of edits) { - for (const textChange of edit.textChanges) { - workspaceEdit.replace(this.client.asUrl(edit.fileName), - tsTextSpanToVsRange(textChange), - textChange.newText); - } - } - return workspaceEdit; - } } class SelectRefactorCommand implements Command { @@ -137,7 +125,7 @@ export default class TypeScriptRefactorProvider implements vscode.CodeActionProv } const range = editor.selection; - const args: Proto.GetApplicableRefactorsRequestArgs = vsRangeToTsFileRange(file, range); + const args: Proto.GetApplicableRefactorsRequestArgs = typeConverters.Range.toFileRangeRequestArgs(file, range); try { const response = await this.client.execute('getApplicableRefactors', args, token); if (!response || !response.body) { diff --git a/extensions/typescript/src/features/referenceProvider.ts b/extensions/typescript-language-features/src/features/referenceProvider.ts similarity index 83% rename from extensions/typescript/src/features/referenceProvider.ts rename to extensions/typescript-language-features/src/features/referenceProvider.ts index a5892d0accd..9fde45687e9 100644 --- a/extensions/typescript/src/features/referenceProvider.ts +++ b/extensions/typescript-language-features/src/features/referenceProvider.ts @@ -6,11 +6,11 @@ import { ReferenceProvider, Location, TextDocument, Position, CancellationToken } from 'vscode'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; export default class TypeScriptReferenceSupport implements ReferenceProvider { public constructor( - private client: ITypeScriptServiceClient) { } + private readonly client: ITypeScriptServiceClient) { } public async provideReferences( document: TextDocument, @@ -23,7 +23,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { return []; } - const args = vsPositionToTsFileLocation(filepath, position); + const args = typeConverters.Position.toFileLocationRequestArgs(filepath, position); try { const msg = await this.client.execute('references', args, token); if (!msg.body) { @@ -36,7 +36,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { continue; } const url = this.client.asUrl(ref.file); - const location = new Location(url, tsTextSpanToVsRange(ref)); + const location = typeConverters.Location.fromTextSpan(url, ref); result.push(location); } return result; diff --git a/extensions/typescript/src/features/referencesCodeLensProvider.ts b/extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts similarity index 90% rename from extensions/typescript/src/features/referencesCodeLensProvider.ts rename to extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts index 098a3469f3b..fdff948985d 100644 --- a/extensions/typescript/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeLens, CancellationToken, TextDocument, Range, Location, workspace } from 'vscode'; +import { CodeLens, CancellationToken, TextDocument, Range, workspace } from 'vscode'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, CachedNavTreeResponse } from './baseCodeLensProvider'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -37,7 +37,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase public resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args = vsPositionToTsFileLocation(codeLens.file, codeLens.range.start); + const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); return this.client.execute('references', args, token).then(response => { if (!response || !response.body) { throw codeLens; @@ -45,7 +45,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase const locations = response.body.refs .map(reference => - new Location(this.client.asUrl(reference.file), tsTextSpanToVsRange(reference))) + typeConverters.Location.fromTextSpan(this.client.asUrl(reference.file), reference)) .filter(location => // Exclude original definition from references !(location.uri.toString() === codeLens.document.toString() && diff --git a/extensions/typescript/src/features/renameProvider.ts b/extensions/typescript-language-features/src/features/renameProvider.ts similarity index 62% rename from extensions/typescript/src/features/renameProvider.ts rename to extensions/typescript-language-features/src/features/renameProvider.ts index 15f94368315..845cf13854e 100644 --- a/extensions/typescript/src/features/renameProvider.ts +++ b/extensions/typescript-language-features/src/features/renameProvider.ts @@ -7,11 +7,12 @@ import { RenameProvider, WorkspaceEdit, TextDocument, Position, CancellationToke import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; export default class TypeScriptRenameProvider implements RenameProvider { public constructor( - private client: ITypeScriptServiceClient) { } + private readonly client: ITypeScriptServiceClient + ) { } public async provideRenameEdits( document: TextDocument, @@ -19,42 +20,48 @@ export default class TypeScriptRenameProvider implements RenameProvider { newName: string, token: CancellationToken ): Promise { - const filepath = this.client.normalizePath(document.uri); - if (!filepath) { + const file = this.client.normalizePath(document.uri); + if (!file) { return null; } const args: Proto.RenameRequestArgs = { - ...vsPositionToTsFileLocation(filepath, position), + ...typeConverters.Position.toFileLocationRequestArgs(file, position), findInStrings: false, findInComments: false }; try { const response = await this.client.execute('rename', args, token); - const renameResponse = response.body; - if (!renameResponse) { + if (!response.body) { return null; } - const renameInfo = renameResponse.info; + const renameInfo = response.body.info; if (!renameInfo.canRename) { return Promise.reject(renameInfo.localizedErrorMessage); } - const result = new WorkspaceEdit(); - for (const spanGroup of renameResponse.locs) { - const resource = this.client.asUrl(spanGroup.file); - if (!resource) { - continue; - } - for (const textSpan of spanGroup.locs) { - result.replace(resource, tsTextSpanToVsRange(textSpan), newName); - } - } - return result; - } catch (e) { + + return this.toWorkspaceEdit(response.body.locs, newName); + } catch { // noop } return null; } + + private toWorkspaceEdit( + locations: ReadonlyArray, + newName: string + ) { + const result = new WorkspaceEdit(); + for (const spanGroup of locations) { + const resource = this.client.asUrl(spanGroup.file); + if (resource) { + for (const textSpan of spanGroup.locs) { + result.replace(resource, typeConverters.Range.fromTextSpan(textSpan), newName); + } + } + } + return result; + } } \ No newline at end of file diff --git a/extensions/typescript/src/features/signatureHelpProvider.ts b/extensions/typescript-language-features/src/features/signatureHelpProvider.ts similarity index 92% rename from extensions/typescript/src/features/signatureHelpProvider.ts rename to extensions/typescript-language-features/src/features/signatureHelpProvider.ts index 92a975c8187..5942c69286a 100644 --- a/extensions/typescript/src/features/signatureHelpProvider.ts +++ b/extensions/typescript-language-features/src/features/signatureHelpProvider.ts @@ -8,7 +8,7 @@ import { SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterIn import * as Previewer from '../utils/previewer'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { vsPositionToTsFileLocation } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; export default class TypeScriptSignatureHelpProvider implements SignatureHelpProvider { @@ -21,7 +21,7 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro if (!filepath) { return null; } - const args: Proto.SignatureHelpRequestArgs = vsPositionToTsFileLocation(filepath, position); + const args: Proto.SignatureHelpRequestArgs = typeConverters.Position.toFileLocationRequestArgs(filepath, position); const response = await this.client.execute('signatureHelp', args, token); const info = response.body; diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript-language-features/src/features/taskProvider.ts similarity index 100% rename from extensions/typescript/src/features/taskProvider.ts rename to extensions/typescript-language-features/src/features/taskProvider.ts diff --git a/extensions/typescript/src/features/typeDefinitionProvider.ts b/extensions/typescript-language-features/src/features/typeDefinitionProvider.ts similarity index 100% rename from extensions/typescript/src/features/typeDefinitionProvider.ts rename to extensions/typescript-language-features/src/features/typeDefinitionProvider.ts diff --git a/extensions/typescript/src/features/workspaceSymbolProvider.ts b/extensions/typescript-language-features/src/features/workspaceSymbolProvider.ts similarity index 76% rename from extensions/typescript/src/features/workspaceSymbolProvider.ts rename to extensions/typescript-language-features/src/features/workspaceSymbolProvider.ts index fb16385887f..206c3f41194 100644 --- a/extensions/typescript/src/features/workspaceSymbolProvider.ts +++ b/extensions/typescript-language-features/src/features/workspaceSymbolProvider.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Location, CancellationToken } from 'vscode'; +import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange } from '../utils/convert'; +import * as typeConverters from '../utils/typeConverters'; function getSymbolKind(item: Proto.NavtoItem): SymbolKind { switch (item.kind) { @@ -23,32 +23,15 @@ function getSymbolKind(item: Proto.NavtoItem): SymbolKind { export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbolProvider { public constructor( - private client: ITypeScriptServiceClient, - private modeIds: string[] + private readonly client: ITypeScriptServiceClient, + private readonly modeIds: string[] ) { } - public async provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { - // typescript wants to have a resource even when asking - // general questions so we check the active editor. If this - // doesn't match we take the first TS document. - let uri: Uri | undefined = undefined; - const editor = window.activeTextEditor; - if (editor) { - const document = editor.document; - if (document && this.modeIds.indexOf(document.languageId) >= 0) { - uri = document.uri; - } - } - if (!uri) { - const documents = workspace.textDocuments; - for (const document of documents) { - if (this.modeIds.indexOf(document.languageId) >= 0) { - uri = document.uri; - break; - } - } - } - + public async provideWorkspaceSymbols( + search: string, + token: CancellationToken + ): Promise { + const uri = this.getUri(); if (!uri) { return []; } @@ -57,6 +40,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo if (!filepath) { return []; } + const args: Proto.NavtoRequestArgs = { file: filepath, searchValue: search @@ -71,10 +55,9 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo if (!item.containerName && item.kind === 'alias') { continue; } - const range = tsTextSpanToVsRange(item); const label = TypeScriptWorkspaceSymbolProvider.getLabel(item); result.push(new SymbolInformation(label, getSymbolKind(item), item.containerName || '', - new Location(this.client.asUrl(item.file), range))); + typeConverters.Location.fromTextSpan(this.client.asUrl(item.file), item))); } return result; } @@ -86,4 +69,26 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo } return label; } + + private getUri(): Uri | undefined { + // typescript wants to have a resource even when asking + // general questions so we check the active editor. If this + // doesn't match we take the first TS document. + + const editor = window.activeTextEditor; + if (editor) { + const document = editor.document; + if (document && this.modeIds.indexOf(document.languageId) >= 0) { + return document.uri; + } + } + + const documents = workspace.textDocuments; + for (const document of documents) { + if (this.modeIds.indexOf(document.languageId) >= 0) { + return document.uri; + } + } + return undefined; + } } \ No newline at end of file diff --git a/extensions/typescript/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts similarity index 92% rename from extensions/typescript/src/languageProvider.ts rename to extensions/typescript-language-features/src/languageProvider.ts index f65faf17c93..e4c4f7de60d 100644 --- a/extensions/typescript/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -14,7 +14,7 @@ import TypingsStatus from './utils/typingsStatus'; import FormattingConfigurationManager from './features/formattingConfigurationManager'; import * as languageConfigurations from './utils/languageConfigurations'; import { CommandManager } from './utils/commandManager'; -import DiagnosticsManager from './features/diagnostics'; +import { DiagnosticsManager, DiagnosticKind } from './features/diagnostics'; import { LanguageDescription } from './utils/languageDescription'; import * as fileSchemes from './utils/fileSchemes'; import { CachedNavTreeResponse } from './features/baseCodeLensProvider'; @@ -22,6 +22,7 @@ import { memoize } from './utils/memoize'; import { disposeAll } from './utils/dipose'; const validateSetting = 'validate.enable'; +const suggestionSetting = 'suggestionActions.enabled'; const foldingSetting = 'typescript.experimental.syntaxFolding'; export default class LanguageProvider { @@ -32,6 +33,7 @@ export default class LanguageProvider { private readonly toUpdateOnConfigurationChanged: ({ updateConfiguration: () => void })[] = []; private _validate: boolean = true; + private _enableSuggestionDiagnostics: boolean = true; private readonly disposables: Disposable[] = []; private readonly versionDependentDisposables: Disposable[] = []; @@ -106,6 +108,8 @@ export default class LanguageProvider { this.disposables.push(formattingProviderManager); this.toUpdateOnConfigurationChanged.push(formattingProviderManager); + const cachedResponse = new CachedNavTreeResponse(); + this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/jsDocCompletionProvider')).default(client, commandManager), '*')); this.disposables.push(languages.registerHoverProvider(selector, new (await import('./features/hoverProvider')).default(client))); this.disposables.push(languages.registerDefinitionProvider(selector, new (await import('./features/definitionProvider')).default(client))); @@ -114,7 +118,7 @@ export default class LanguageProvider { this.disposables.push(languages.registerDocumentSymbolProvider(selector, new (await import('./features/documentSymbolProvider')).default(client))); this.disposables.push(languages.registerSignatureHelpProvider(selector, new (await import('./features/signatureHelpProvider')).default(client), '(', ',')); this.disposables.push(languages.registerRenameProvider(selector, new (await import('./features/renameProvider')).default(client))); - this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/quickFixProvider')).default(client, this.formattingOptionsManager, commandManager, this.diagnosticsManager))); + this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/quickFixProvider')).default(client, this.formattingOptionsManager, commandManager, this.diagnosticsManager, this.bufferSyncSupport))); this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, commandManager))); await this.initFoldingProvider(); @@ -127,8 +131,6 @@ export default class LanguageProvider { this.registerVersionDependentProviders(); - const cachedResponse = new CachedNavTreeResponse(); - const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, this.description.id, cachedResponse); referenceCodeLensProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider); @@ -150,7 +152,7 @@ export default class LanguageProvider { private async initFoldingProvider(): Promise { let enable = workspace.getConfiguration().get(foldingSetting, false); - if (enable) { + if (enable && this.client.apiVersion.has280Features()) { if (!this.foldingProviderRegistration) { this.foldingProviderRegistration = languages.registerFoldingProvider(this.documentSelector, new (await import('./features/folderingProvider')).default(this.client)); } @@ -165,6 +167,7 @@ export default class LanguageProvider { private configurationChanged(): void { const config = workspace.getConfiguration(this.id); this.updateValidate(config.get(validateSetting, true)); + this.updateSuggestionDiagnostics(config.get(suggestionSetting, true)); for (const toUpdate of this.toUpdateOnConfigurationChanged) { toUpdate.updateConfiguration(); @@ -204,6 +207,18 @@ export default class LanguageProvider { } } + private updateSuggestionDiagnostics(value: boolean) { + if (this._enableSuggestionDiagnostics === value) { + return; + } + + this._enableSuggestionDiagnostics = value; + this.diagnosticsManager.enableSuggestions = value; + if (value) { + this.triggerAllDiagnostics(); + } + } + public reInitialize(): void { this.diagnosticsManager.reInitialize(); this.bufferSyncSupport.reOpenDocuments(); @@ -233,12 +248,8 @@ export default class LanguageProvider { this.bufferSyncSupport.requestAllDiagnostics(); } - public syntaxDiagnosticsReceived(file: Uri, syntaxDiagnostics: Diagnostic[]): void { - this.diagnosticsManager.syntaxDiagnosticsReceived(file, syntaxDiagnostics); - } - - public semanticDiagnosticsReceived(file: Uri, semanticDiagnostics: Diagnostic[]): void { - this.diagnosticsManager.semanticDiagnosticsReceived(file, semanticDiagnostics); + public diagnosticsReceived(diagnosticsKind: DiagnosticKind, file: Uri, syntaxDiagnostics: Diagnostic[]): void { + this.diagnosticsManager.diagnosticsReceived(diagnosticsKind, file, syntaxDiagnostics); } public configFileDiagnosticsReceived(file: Uri, diagnostics: Diagnostic[]): void { diff --git a/extensions/typescript/src/protocol.const.ts b/extensions/typescript-language-features/src/protocol.const.ts similarity index 97% rename from extensions/typescript/src/protocol.const.ts rename to extensions/typescript-language-features/src/protocol.const.ts index 822e05d2b21..25cb015316b 100644 --- a/extensions/typescript/src/protocol.const.ts +++ b/extensions/typescript-language-features/src/protocol.const.ts @@ -36,6 +36,6 @@ export class Kind { export class DiagnosticCategory { public static readonly error = 'error'; - public static readonly warning = 'warning'; + public static readonly suggestion = 'suggestion'; } \ No newline at end of file diff --git a/extensions/typescript/src/protocol.d.ts b/extensions/typescript-language-features/src/protocol.d.ts similarity index 100% rename from extensions/typescript/src/protocol.d.ts rename to extensions/typescript-language-features/src/protocol.d.ts diff --git a/extensions/typescript/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts similarity index 91% rename from extensions/typescript/src/typeScriptServiceClientHost.ts rename to extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index 9d552927c72..7e3b170d968 100644 --- a/extensions/typescript/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -19,11 +19,12 @@ import LanguageProvider from './languageProvider'; import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import VersionStatus from './utils/versionStatus'; import { TypeScriptServerPlugin } from './utils/plugins'; -import { tsLocationToVsPosition } from './utils/convert'; +import * as typeConverters from './utils/typeConverters'; import { CommandManager } from './utils/commandManager'; import { LanguageDescription } from './utils/languageDescription'; import LogDirectoryProvider from './utils/logDirectoryProvider'; import { disposeAll } from './utils/dipose'; +import { DiagnosticKind } from './features/diagnostics'; // Style check diagnostics that can be reported as warnings const styleCheckDiagnostics = [ @@ -70,8 +71,10 @@ export default class TypeScriptServiceClientHost { this.client = new TypeScriptServiceClient(workspaceState, version => this.versionStatus.onDidChangeTypeScriptVersion(version), plugins, logDirectoryProvider); this.disposables.push(this.client); - this.client.onSyntaxDiagnosticsReceived(({ resource, diagnostics }) => this.syntaxDiagnosticsReceived(resource, diagnostics), null, this.disposables); - this.client.onSemanticDiagnosticsReceived(({ resource, diagnostics }) => this.semanticDiagnosticsReceived(resource, diagnostics), null, this.disposables); + this.client.onDiagnosticsReceived(({ kind, resource, diagnostics }) => { + this.diagnosticsReceived(kind, resource, diagnostics); + }, null, this.disposables); + this.client.onConfigDiagnosticsReceived(diag => this.configFileDiagnosticsReceived(diag), null, this.disposables); this.client.onResendModelsRequested(() => this.populateService(), null, this.disposables); @@ -170,19 +173,15 @@ export default class TypeScriptServiceClientHost { }); } - private async syntaxDiagnosticsReceived(resource: Uri, diagnostics: Proto.Diagnostic[]): Promise { + private async diagnosticsReceived( + kind: DiagnosticKind, + resource: Uri, + diagnostics: Proto.Diagnostic[] + ): Promise { const language = await this.findLanguage(resource); if (language) { - language.syntaxDiagnosticsReceived( - resource, - this.createMarkerDatas(diagnostics, language.diagnosticSource)); - } - } - - private async semanticDiagnosticsReceived(resource: Uri, diagnostics: Proto.Diagnostic[]): Promise { - const language = await this.findLanguage(resource); - if (language) { - language.semanticDiagnosticsReceived( + language.diagnosticsReceived( + kind, resource, this.createMarkerDatas(diagnostics, language.diagnosticSource)); } @@ -245,7 +244,7 @@ export default class TypeScriptServiceClientHost { private tsDiagnosticToVsDiagnostic(diagnostic: Proto.Diagnostic, source: string) { const { start, end, text } = diagnostic; - const range = new Range(tsLocationToVsPosition(start), tsLocationToVsPosition(end)); + const range = new Range(typeConverters.Position.fromLocation(start), typeConverters.Position.fromLocation(end)); const converted = new Diagnostic(range, text); converted.severity = this.getDiagnosticSeverity(diagnostic); converted.source = diagnostic.source || source; @@ -267,6 +266,9 @@ export default class TypeScriptServiceClientHost { case PConst.DiagnosticCategory.warning: return DiagnosticSeverity.Warning; + case PConst.DiagnosticCategory.suggestion: + return DiagnosticSeverity.Hint; + default: return DiagnosticSeverity.Error; } diff --git a/extensions/typescript/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts similarity index 94% rename from extensions/typescript/src/typescriptService.ts rename to extensions/typescript-language-features/src/typescriptService.ts index 1bf8f12789d..cc8b4491050 100644 --- a/extensions/typescript/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - import { CancellationToken, Uri, Event } from 'vscode'; import * as Proto from './protocol'; import API from './utils/api'; @@ -16,7 +15,7 @@ export interface ITypeScriptServiceClient { asUrl(filepath: string): Uri; getWorkspaceRootForResource(resource: Uri): string | undefined; - onTsServerStarted: Event; + onTsServerStarted: Event; onProjectLanguageServiceStateChanged: Event; onDidBeginInstallTypings: Event; onDidEndInstallTypings: Event; @@ -58,7 +57,7 @@ export interface ITypeScriptServiceClient { execute(command: 'getApplicableRefactors', args: Proto.GetApplicableRefactorsRequestArgs, token?: CancellationToken): Promise; execute(command: 'getEditsForRefactor', args: Proto.GetEditsForRefactorRequestArgs, token?: CancellationToken): Promise; execute(command: 'applyCodeActionCommand', args: Proto.ApplyCodeActionCommandRequestArgs, token?: CancellationToken): Promise; - // execute(command: 'compileOnSaveAffectedFileList', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise; - // execute(command: 'compileOnSaveEmitFile', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise; + execute(command: 'organizeImports', args: Proto.OrganizeImportsRequestArgs, token?: CancellationToken): Promise; + execute(command: 'getOutliningSpans', args: Proto.FileRequestArgs, token: CancellationToken): Promise; execute(command: string, args: any, expectedResult: boolean | CancellationToken, token?: CancellationToken): Promise; } \ No newline at end of file diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts similarity index 94% rename from extensions/typescript/src/typescriptServiceClient.ts rename to extensions/typescript-language-features/src/typescriptServiceClient.ts index f41adaff666..5c4eb3c4ed1 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -29,6 +29,8 @@ import * as fileSchemes from './utils/fileSchemes'; import { inferredProjectConfig } from './utils/tsconfig'; import LogDirectoryProvider from './utils/logDirectoryProvider'; import { disposeAll } from './utils/dipose'; +import { DiagnosticKind } from './features/diagnostics'; +import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider'; const localize = nls.loadMessageBundle(); @@ -140,6 +142,7 @@ class ForkedTsServerProcess { } export interface TsDiagnostics { + readonly kind: DiagnosticKind; readonly resource: Uri; readonly diagnostics: Proto.Diagnostic[]; } @@ -152,6 +155,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient private _onReady?: { promise: Promise; resolve: () => void; reject: () => void; }; private _configuration: TypeScriptServiceConfiguration; private versionProvider: TypeScriptVersionProvider; + private pluginPathsProvider: TypeScriptPluginPathsProvider; private versionPicker: TypeScriptVersionPicker; private tracer: Tracer; @@ -168,7 +172,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient private requestQueue: RequestQueue; private callbacks: CallbackMap; - private readonly _onTsServerStarted = new EventEmitter(); + private readonly _onTsServerStarted = new EventEmitter(); private readonly _onProjectLanguageServiceStateChanged = new EventEmitter(); private readonly _onDidBeginInstallTypings = new EventEmitter(); private readonly _onDidEndInstallTypings = new EventEmitter(); @@ -208,6 +212,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient this.callbacks = new CallbackMap(); this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace(); this.versionProvider = new TypeScriptVersionProvider(this._configuration); + this.pluginPathsProvider = new TypeScriptPluginPathsProvider(this._configuration); this.versionPicker = new TypeScriptVersionPicker(this.versionProvider, this.workspaceState); this._apiVersion = API.defaultVersion; @@ -219,6 +224,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace(); this.versionProvider.updateConfiguration(this._configuration); + this.pluginPathsProvider.updateConfiguration(this._configuration); this.tracer.updateConfiguration(); if (this.servicePromise) { @@ -237,11 +243,8 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient this.disposables.push(this.telemetryReporter); } - private _onSyntaxDiagnosticsReceived = new EventEmitter(); - public get onSyntaxDiagnosticsReceived(): Event { return this._onSyntaxDiagnosticsReceived.event; } - - private _onSemanticDiagnosticsReceived = new EventEmitter(); - public get onSemanticDiagnosticsReceived(): Event { return this._onSemanticDiagnosticsReceived.event; } + private _onDiagnosticsReceived = new EventEmitter(); + public get onDiagnosticsReceived(): Event { return this._onDiagnosticsReceived.event; } private _onConfigDiagnosticsReceived = new EventEmitter(); public get onConfigDiagnosticsReceived(): Event { return this._onConfigDiagnosticsReceived.event; } @@ -254,6 +257,11 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } public dispose() { + this._onTsServerStarted.dispose(); + this._onDidBeginInstallTypings.dispose(); + this._onDidEndInstallTypings.dispose(); + this._onTypesInstallerInitializationFailed.dispose(); + if (this.servicePromise) { this.servicePromise.then(childProcess => { childProcess.kill(); @@ -261,8 +269,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } disposeAll(this.disposables); - this._onSyntaxDiagnosticsReceived.dispose(); - this._onSemanticDiagnosticsReceived.dispose(); + this._onDiagnosticsReceived.dispose(); this._onConfigDiagnosticsReceived.dispose(); this._onResendModelsRequested.dispose(); } @@ -285,7 +292,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } } - get onTsServerStarted(): Event { + get onTsServerStarted(): Event { return this._onTsServerStarted.event; } @@ -425,7 +432,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient this._onReady!.resolve(); resolve(handle); - this._onTsServerStarted.fire(); + this._onTsServerStarted.fire(currentVersion.version); this.serviceStarted(resendModels); }); @@ -788,7 +795,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient this.tracer.traceEvent(event); this.dispatchEvent(event); } else { - throw new Error('Unknown message type ' + message.type + ' recevied'); + throw new Error('Unknown message type ' + message.type + ' received'); } } finally { this.sendNextRequests(); @@ -798,27 +805,18 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient private dispatchEvent(event: Proto.Event) { switch (event.event) { case 'syntaxDiag': - { - const diagnosticEvent: Proto.DiagnosticEvent = event; - if (diagnosticEvent.body && diagnosticEvent.body.diagnostics) { - this._onSyntaxDiagnosticsReceived.fire({ - resource: this.asUrl(diagnosticEvent.body.file), - diagnostics: diagnosticEvent.body.diagnostics - }); - } - break; - } case 'semanticDiag': - { - const diagnosticEvent: Proto.DiagnosticEvent = event; - if (diagnosticEvent.body && diagnosticEvent.body.diagnostics) { - this._onSemanticDiagnosticsReceived.fire({ - resource: this.asUrl(diagnosticEvent.body.file), - diagnostics: diagnosticEvent.body.diagnostics - }); - } - break; + case 'suggestionDiag': + const diagnosticEvent: Proto.DiagnosticEvent = event; + if (diagnosticEvent.body && diagnosticEvent.body.diagnostics) { + this._onDiagnosticsReceived.fire({ + kind: getDignosticsKind(event), + resource: this.asUrl(diagnosticEvent.body.file), + diagnostics: diagnosticEvent.body.diagnostics + }); } + break; + case 'configFileDiag': this._onConfigDiagnosticsReceived.fire(event as Proto.ConfigFileDiagnosticEvent); break; @@ -944,12 +942,19 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } if (this.apiVersion.has230Features()) { + const pluginPaths = this.pluginPathsProvider.getPluginPaths(); + if (this.plugins.length) { args.push('--globalPlugins', this.plugins.map(x => x.name).join(',')); + if (currentVersion.path === this.versionProvider.defaultVersion.path) { - args.push('--pluginProbeLocations', this.plugins.map(x => x.path).join(',')); + pluginPaths.push(...this.plugins.map(x => x.path)); } } + + if (pluginPaths.length !== 0) { + args.push('--pluginProbeLocations', pluginPaths.join(',')); + } } if (this.apiVersion.has234Features()) { @@ -967,7 +972,6 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient return args; } - private getDebugPort(): number | undefined { const value = process.env['TSS_DEBUG']; if (value) { @@ -989,4 +993,13 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient const getTsLocale = (configuration: TypeScriptServiceConfiguration): string | undefined => (configuration.locale ? configuration.locale - : env.language); \ No newline at end of file + : env.language); + +function getDignosticsKind(event: Proto.Event) { + switch (event.event) { + case 'syntaxDiag': return DiagnosticKind.Syntax; + case 'semanticDiag': return DiagnosticKind.Semantic; + case 'suggestionDiag': return DiagnosticKind.Suggestion; + } + throw new Error('Unknown dignostics kind'); +} diff --git a/extensions/typescript/src/typings/collections.d.ts b/extensions/typescript-language-features/src/typings/collections.d.ts similarity index 100% rename from extensions/typescript/src/typings/collections.d.ts rename to extensions/typescript-language-features/src/typings/collections.d.ts diff --git a/extensions/typescript/src/typings/ref.d.ts b/extensions/typescript-language-features/src/typings/ref.d.ts similarity index 100% rename from extensions/typescript/src/typings/ref.d.ts rename to extensions/typescript-language-features/src/typings/ref.d.ts diff --git a/extensions/typescript/src/utils/api.ts b/extensions/typescript-language-features/src/utils/api.ts similarity index 96% rename from extensions/typescript/src/utils/api.ts rename to extensions/typescript-language-features/src/utils/api.ts index e4103a29231..7dadfd840f1 100644 --- a/extensions/typescript/src/utils/api.ts +++ b/extensions/typescript-language-features/src/utils/api.ts @@ -96,4 +96,9 @@ export default class API { public has270Features(): boolean { return semver.gte(this.version, '2.7.0'); } + + @memoize + public has280Features(): boolean { + return semver.gte(this.version, '2.8.0'); + } } \ No newline at end of file diff --git a/extensions/typescript-language-features/src/utils/arrays.ts b/extensions/typescript-language-features/src/utils/arrays.ts new file mode 100644 index 00000000000..57dbd54a29c --- /dev/null +++ b/extensions/typescript-language-features/src/utils/arrays.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +export function equals(one: T[], other: T[], itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean { + if (one.length !== other.length) { + return false; + } + + for (let i = 0, len = one.length; i < len; i++) { + if (!itemEquals(one[i], other[i])) { + return false; + } + } + + return true; +} \ No newline at end of file diff --git a/extensions/typescript/src/utils/async.ts b/extensions/typescript-language-features/src/utils/async.ts similarity index 100% rename from extensions/typescript/src/utils/async.ts rename to extensions/typescript-language-features/src/utils/async.ts diff --git a/extensions/typescript/src/utils/codeAction.ts b/extensions/typescript-language-features/src/utils/codeAction.ts similarity index 91% rename from extensions/typescript/src/utils/codeAction.ts rename to extensions/typescript-language-features/src/utils/codeAction.ts index 4c05629c78c..984ea6bc9f3 100644 --- a/extensions/typescript/src/utils/codeAction.ts +++ b/extensions/typescript-language-features/src/utils/codeAction.ts @@ -6,14 +6,14 @@ import { WorkspaceEdit, workspace } from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { createWorkspaceEditFromFileCodeEdits } from './workspaceEdit'; +import * as typeConverters from './typeConverters'; export function getEditForCodeAction( client: ITypeScriptServiceClient, action: Proto.CodeAction ): WorkspaceEdit | undefined { return action.changes && action.changes.length - ? createWorkspaceEditFromFileCodeEdits(client, action.changes) + ? typeConverters.WorkspaceEdit.fromFromFileCodeEdits(client, action.changes) : undefined; } diff --git a/extensions/typescript/src/utils/commandManager.ts b/extensions/typescript-language-features/src/utils/commandManager.ts similarity index 85% rename from extensions/typescript/src/utils/commandManager.ts rename to extensions/typescript-language-features/src/utils/commandManager.ts index 359d5b9ca96..7bf1d7e33aa 100644 --- a/extensions/typescript/src/utils/commandManager.ts +++ b/extensions/typescript-language-features/src/utils/commandManager.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; export interface Command { - readonly id: string; + readonly id: string | string[]; execute(...args: any[]): void; } @@ -22,7 +22,9 @@ export class CommandManager { } public register(command: T): T { - this.registerCommand(command.id, command.execute, command); + for (const id of Array.isArray(command.id) ? command.id : [command.id]) { + this.registerCommand(id, command.execute, command); + } return command; } diff --git a/extensions/typescript/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts similarity index 91% rename from extensions/typescript/src/utils/configuration.ts rename to extensions/typescript-language-features/src/utils/configuration.ts index 4976a3ec26a..9359a2bbed0 100644 --- a/extensions/typescript/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { WorkspaceConfiguration, workspace } from 'vscode'; +import * as arrays from './arrays'; export enum TsServerLogLevel { Off, @@ -47,6 +48,7 @@ export class TypeScriptServiceConfiguration { public readonly localTsdk: string | null; public readonly npmLocation: string | null; public readonly tsServerLogLevel: TsServerLogLevel = TsServerLogLevel.Off; + public readonly tsServerPluginPaths: string[]; public readonly checkJs: boolean; public readonly experimentalDecorators: boolean; public readonly disableAutomaticTypeAcquisition: boolean; @@ -63,6 +65,7 @@ export class TypeScriptServiceConfiguration { this.localTsdk = TypeScriptServiceConfiguration.extractLocalTsdk(configuration); this.npmLocation = TypeScriptServiceConfiguration.readNpmLocation(configuration); this.tsServerLogLevel = TypeScriptServiceConfiguration.readTsServerLogLevel(configuration); + this.tsServerPluginPaths = TypeScriptServiceConfiguration.readTsServerPluginPaths(configuration); this.checkJs = TypeScriptServiceConfiguration.readCheckJs(configuration); this.experimentalDecorators = TypeScriptServiceConfiguration.readExperimentalDecorators(configuration); this.disableAutomaticTypeAcquisition = TypeScriptServiceConfiguration.readDisableAutomaticTypeAcquisition(configuration); @@ -76,7 +79,8 @@ export class TypeScriptServiceConfiguration { && this.tsServerLogLevel === other.tsServerLogLevel && this.checkJs === other.checkJs && this.experimentalDecorators === other.experimentalDecorators - && this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition; + && this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition + && arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths); } private static extractGlobalTsdk(configuration: WorkspaceConfiguration): string | null { @@ -100,6 +104,10 @@ export class TypeScriptServiceConfiguration { return TsServerLogLevel.fromString(setting); } + private static readTsServerPluginPaths(configuration: WorkspaceConfiguration): string[] { + return configuration.get('typescript.tsserver.pluginPaths', []); + } + private static readCheckJs(configuration: WorkspaceConfiguration): boolean { return configuration.get('javascript.implicitProjectConfig.checkJs', false); } diff --git a/extensions/typescript/src/utils/dipose.ts b/extensions/typescript-language-features/src/utils/dipose.ts similarity index 100% rename from extensions/typescript/src/utils/dipose.ts rename to extensions/typescript-language-features/src/utils/dipose.ts diff --git a/extensions/typescript/src/utils/electron.ts b/extensions/typescript-language-features/src/utils/electron.ts similarity index 100% rename from extensions/typescript/src/utils/electron.ts rename to extensions/typescript-language-features/src/utils/electron.ts diff --git a/extensions/typescript/src/utils/electronForkStart.ts b/extensions/typescript-language-features/src/utils/electronForkStart.ts similarity index 100% rename from extensions/typescript/src/utils/electronForkStart.ts rename to extensions/typescript-language-features/src/utils/electronForkStart.ts diff --git a/extensions/typescript/src/utils/fileSchemes.ts b/extensions/typescript-language-features/src/utils/fileSchemes.ts similarity index 100% rename from extensions/typescript/src/utils/fileSchemes.ts rename to extensions/typescript-language-features/src/utils/fileSchemes.ts diff --git a/extensions/typescript/src/utils/is.ts b/extensions/typescript-language-features/src/utils/is.ts similarity index 100% rename from extensions/typescript/src/utils/is.ts rename to extensions/typescript-language-features/src/utils/is.ts diff --git a/extensions/typescript/src/utils/languageConfigurations.ts b/extensions/typescript-language-features/src/utils/languageConfigurations.ts similarity index 100% rename from extensions/typescript/src/utils/languageConfigurations.ts rename to extensions/typescript-language-features/src/utils/languageConfigurations.ts diff --git a/extensions/typescript/src/utils/languageDescription.ts b/extensions/typescript-language-features/src/utils/languageDescription.ts similarity index 100% rename from extensions/typescript/src/utils/languageDescription.ts rename to extensions/typescript-language-features/src/utils/languageDescription.ts diff --git a/extensions/typescript/src/utils/languageModeIds.ts b/extensions/typescript-language-features/src/utils/languageModeIds.ts similarity index 68% rename from extensions/typescript/src/utils/languageModeIds.ts rename to extensions/typescript-language-features/src/utils/languageModeIds.ts index 65f8cb0e9ff..5fe187e13db 100644 --- a/extensions/typescript/src/utils/languageModeIds.ts +++ b/extensions/typescript-language-features/src/utils/languageModeIds.ts @@ -3,8 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as vscode from 'vscode'; + export const typescript = 'typescript'; export const typescriptreact = 'typescriptreact'; export const javascript = 'javascript'; export const javascriptreact = 'javascriptreact'; -export const jsxTags = 'jsx-tags'; \ No newline at end of file +export const jsxTags = 'jsx-tags'; + + +export function isSupportedLanguageMode(doc: vscode.TextDocument) { + return vscode.languages.match([typescript, typescriptreact, javascript, javascriptreact], doc) > 0; +} \ No newline at end of file diff --git a/extensions/typescript/src/utils/lazy.ts b/extensions/typescript-language-features/src/utils/lazy.ts similarity index 100% rename from extensions/typescript/src/utils/lazy.ts rename to extensions/typescript-language-features/src/utils/lazy.ts diff --git a/extensions/typescript/src/utils/logDirectoryProvider.ts b/extensions/typescript-language-features/src/utils/logDirectoryProvider.ts similarity index 100% rename from extensions/typescript/src/utils/logDirectoryProvider.ts rename to extensions/typescript-language-features/src/utils/logDirectoryProvider.ts diff --git a/extensions/typescript/src/utils/logger.ts b/extensions/typescript-language-features/src/utils/logger.ts similarity index 100% rename from extensions/typescript/src/utils/logger.ts rename to extensions/typescript-language-features/src/utils/logger.ts diff --git a/extensions/typescript/src/utils/managedFileContext.ts b/extensions/typescript-language-features/src/utils/managedFileContext.ts similarity index 85% rename from extensions/typescript/src/utils/managedFileContext.ts rename to extensions/typescript-language-features/src/utils/managedFileContext.ts index baf4fd704e6..b16f4524061 100644 --- a/extensions/typescript/src/utils/managedFileContext.ts +++ b/extensions/typescript-language-features/src/utils/managedFileContext.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import * as languageModeIds from './languageModeIds'; +import { isSupportedLanguageMode } from './languageModeIds'; /** * When clause context set when the current file is managed by vscode's built-in typescript extension. @@ -46,6 +46,3 @@ export default class ManagedFileContextManager { } } -function isSupportedLanguageMode(doc: vscode.TextDocument) { - return vscode.languages.match([languageModeIds.typescript, languageModeIds.typescriptreact, languageModeIds.javascript, languageModeIds.javascriptreact], doc) > 0; -} diff --git a/extensions/typescript/src/utils/memoize.ts b/extensions/typescript-language-features/src/utils/memoize.ts similarity index 100% rename from extensions/typescript/src/utils/memoize.ts rename to extensions/typescript-language-features/src/utils/memoize.ts diff --git a/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts b/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts new file mode 100644 index 00000000000..e2e39d68801 --- /dev/null +++ b/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as path from 'path'; +import { workspace } from 'vscode'; + +import { TypeScriptServiceConfiguration } from './configuration'; +import { RelativeWorkspacePathResolver } from './relativePathResolver'; + +export class TypeScriptPluginPathsProvider { + public readonly relativePathResolver: RelativeWorkspacePathResolver = new RelativeWorkspacePathResolver(); + + public constructor( + private configuration: TypeScriptServiceConfiguration + ) { } + + public updateConfiguration(configuration: TypeScriptServiceConfiguration): void { + this.configuration = configuration; + } + + public getPluginPaths(): string[] { + const pluginPaths = []; + for (const pluginPath of this.configuration.tsServerPluginPaths) { + pluginPaths.push(...this.resolvePluginPath(pluginPath)); + } + return pluginPaths; + } + + private resolvePluginPath(pluginPath: string): string[] { + if (path.isAbsolute(pluginPath)) { + return [pluginPath]; + } + + const workspacePath = this.relativePathResolver.asAbsoluteWorkspacePath(pluginPath); + if (workspacePath !== undefined) { + return [workspacePath]; + } + + return (workspace.workspaceFolders || []) + .map(workspaceFolder => path.join(workspaceFolder.uri.fsPath, pluginPath)); + } +} \ No newline at end of file diff --git a/extensions/typescript/src/utils/plugins.ts b/extensions/typescript-language-features/src/utils/plugins.ts similarity index 100% rename from extensions/typescript/src/utils/plugins.ts rename to extensions/typescript-language-features/src/utils/plugins.ts diff --git a/extensions/typescript/src/utils/previewer.ts b/extensions/typescript-language-features/src/utils/previewer.ts similarity index 100% rename from extensions/typescript/src/utils/previewer.ts rename to extensions/typescript-language-features/src/utils/previewer.ts diff --git a/extensions/typescript/src/utils/projectStatus.ts b/extensions/typescript-language-features/src/utils/projectStatus.ts similarity index 100% rename from extensions/typescript/src/utils/projectStatus.ts rename to extensions/typescript-language-features/src/utils/projectStatus.ts diff --git a/extensions/typescript/src/utils/regexp.ts b/extensions/typescript-language-features/src/utils/regexp.ts similarity index 100% rename from extensions/typescript/src/utils/regexp.ts rename to extensions/typescript-language-features/src/utils/regexp.ts diff --git a/extensions/typescript-language-features/src/utils/relativePathResolver.ts b/extensions/typescript-language-features/src/utils/relativePathResolver.ts new file mode 100644 index 00000000000..e424fca126a --- /dev/null +++ b/extensions/typescript-language-features/src/utils/relativePathResolver.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as path from 'path'; +import { workspace } from 'vscode'; + +export class RelativeWorkspacePathResolver { + public asAbsoluteWorkspacePath(relativePath: string): string | undefined { + for (const root of workspace.workspaceFolders || []) { + const rootPrefixes = [`./${root.name}/`, `${root.name}/`, `.\\${root.name}\\`, `${root.name}\\`]; + for (const rootPrefix of rootPrefixes) { + if (relativePath.startsWith(rootPrefix)) { + return path.join(root.uri.fsPath, relativePath.replace(rootPrefix, '')); + } + } + } + + return undefined; + } +} \ No newline at end of file diff --git a/extensions/typescript/src/utils/telemetry.ts b/extensions/typescript-language-features/src/utils/telemetry.ts similarity index 100% rename from extensions/typescript/src/utils/telemetry.ts rename to extensions/typescript-language-features/src/utils/telemetry.ts diff --git a/extensions/typescript/src/utils/tracer.ts b/extensions/typescript-language-features/src/utils/tracer.ts similarity index 100% rename from extensions/typescript/src/utils/tracer.ts rename to extensions/typescript-language-features/src/utils/tracer.ts diff --git a/extensions/typescript/src/utils/tsconfig.ts b/extensions/typescript-language-features/src/utils/tsconfig.ts similarity index 100% rename from extensions/typescript/src/utils/tsconfig.ts rename to extensions/typescript-language-features/src/utils/tsconfig.ts diff --git a/extensions/typescript/src/utils/tsconfigProvider.ts b/extensions/typescript-language-features/src/utils/tsconfigProvider.ts similarity index 100% rename from extensions/typescript/src/utils/tsconfigProvider.ts rename to extensions/typescript-language-features/src/utils/tsconfigProvider.ts diff --git a/extensions/typescript-language-features/src/utils/typeConverters.ts b/extensions/typescript-language-features/src/utils/typeConverters.ts new file mode 100644 index 00000000000..8975e325508 --- /dev/null +++ b/extensions/typescript-language-features/src/utils/typeConverters.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Helpers for converting FROM vscode types TO ts types + */ + +import * as vscode from 'vscode'; +import * as Proto from '../protocol'; +import { ITypeScriptServiceClient } from '../typescriptService'; + +export namespace Range { + export const fromTextSpan = (span: Proto.TextSpan): vscode.Range => + new vscode.Range( + span.start.line - 1, span.start.offset - 1, + span.end.line - 1, span.end.offset - 1); + + export const toFileRangeRequestArgs = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ + file, + startLine: range.start.line + 1, + startOffset: range.start.character + 1, + endLine: range.end.line + 1, + endOffset: range.end.character + 1 + }); +} + +export namespace Position { + export const fromLocation = (tslocation: Proto.Location): vscode.Position => + new vscode.Position(tslocation.line - 1, tslocation.offset - 1); + + export const toFileLocationRequestArgs = (file: string, position: vscode.Position): Proto.FileLocationRequestArgs => ({ + file, + line: position.line + 1, + offset: position.character + 1 + }); +} + +export namespace Location { + export const fromTextSpan = (resource: vscode.Uri, tsTextSpan: Proto.TextSpan): vscode.Location => + new vscode.Location(resource, Range.fromTextSpan(tsTextSpan)); +} + +export namespace TextEdit { + export const fromCodeEdit = (edit: Proto.CodeEdit): vscode.TextEdit => + new vscode.TextEdit( + Range.fromTextSpan(edit), + edit.newText); +} + +export namespace WorkspaceEdit { + export function fromFromFileCodeEdits( + client: ITypeScriptServiceClient, + edits: Iterable + ): vscode.WorkspaceEdit { + const workspaceEdit = new vscode.WorkspaceEdit(); + for (const edit of edits) { + for (const textChange of edit.textChanges) { + workspaceEdit.replace(client.asUrl(edit.fileName), + Range.fromTextSpan(textChange), + textChange.newText); + } + } + + return workspaceEdit; + } +} diff --git a/extensions/typescript/src/utils/typingsStatus.ts b/extensions/typescript-language-features/src/utils/typingsStatus.ts similarity index 100% rename from extensions/typescript/src/utils/typingsStatus.ts rename to extensions/typescript-language-features/src/utils/typingsStatus.ts diff --git a/extensions/typescript/src/utils/versionPicker.ts b/extensions/typescript-language-features/src/utils/versionPicker.ts similarity index 100% rename from extensions/typescript/src/utils/versionPicker.ts rename to extensions/typescript-language-features/src/utils/versionPicker.ts diff --git a/extensions/typescript/src/utils/versionProvider.ts b/extensions/typescript-language-features/src/utils/versionProvider.ts similarity index 92% rename from extensions/typescript/src/utils/versionProvider.ts rename to extensions/typescript-language-features/src/utils/versionProvider.ts index 4f3d4ed85f4..25ecb3355d1 100644 --- a/extensions/typescript/src/utils/versionProvider.ts +++ b/extensions/typescript-language-features/src/utils/versionProvider.ts @@ -11,6 +11,7 @@ import * as fs from 'fs'; import { workspace, window } from 'vscode'; import { TypeScriptServiceConfiguration } from './configuration'; +import { RelativeWorkspacePathResolver } from './relativePathResolver'; import API from './api'; @@ -91,6 +92,8 @@ export class TypeScriptVersion { export class TypeScriptVersionProvider { + private readonly relativePathResolver: RelativeWorkspacePathResolver = new RelativeWorkspacePathResolver(); + public constructor( private configuration: TypeScriptServiceConfiguration ) { } @@ -165,14 +168,9 @@ export class TypeScriptVersionProvider { return [new TypeScriptVersion(tsdkPathSetting)]; } - for (const root of workspace.workspaceFolders || []) { - const rootPrefixes = [`./${root.name}/`, `${root.name}/`, `.\\${root.name}\\`, `${root.name}\\`]; - for (const rootPrefix of rootPrefixes) { - if (tsdkPathSetting.startsWith(rootPrefix)) { - const workspacePath = path.join(root.uri.fsPath, tsdkPathSetting.replace(rootPrefix, '')); - return [new TypeScriptVersion(workspacePath, tsdkPathSetting)]; - } - } + const workspacePath = this.relativePathResolver.asAbsoluteWorkspacePath(tsdkPathSetting); + if (workspacePath !== undefined) { + return [new TypeScriptVersion(workspacePath, tsdkPathSetting)]; } return this.loadTypeScriptVersionsFromPath(tsdkPathSetting); diff --git a/extensions/typescript/src/utils/versionStatus.ts b/extensions/typescript-language-features/src/utils/versionStatus.ts similarity index 100% rename from extensions/typescript/src/utils/versionStatus.ts rename to extensions/typescript-language-features/src/utils/versionStatus.ts diff --git a/extensions/typescript/src/utils/wireProtocol.ts b/extensions/typescript-language-features/src/utils/wireProtocol.ts similarity index 100% rename from extensions/typescript/src/utils/wireProtocol.ts rename to extensions/typescript-language-features/src/utils/wireProtocol.ts diff --git a/extensions/typescript/tsconfig.json b/extensions/typescript-language-features/tsconfig.json similarity index 100% rename from extensions/typescript/tsconfig.json rename to extensions/typescript-language-features/tsconfig.json diff --git a/extensions/typescript/yarn.lock b/extensions/typescript-language-features/yarn.lock similarity index 100% rename from extensions/typescript/yarn.lock rename to extensions/typescript-language-features/yarn.lock diff --git a/extensions/typescript/src/features/diagnostics.ts b/extensions/typescript/src/features/diagnostics.ts deleted file mode 100644 index 2972fbf5857..00000000000 --- a/extensions/typescript/src/features/diagnostics.ts +++ /dev/null @@ -1,99 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Diagnostic, DiagnosticCollection, languages, Uri } from 'vscode'; - -class DiagnosticSet { - private _map: ObjectMap = Object.create(null); - - public set( - file: Uri, - diagnostics: Diagnostic[] - ) { - this._map[this.key(file)] = diagnostics; - } - - public get( - file: Uri - ): Diagnostic[] { - return this._map[this.key(file)] || []; - } - - public clear(): void { - this._map = Object.create(null); - } - - private key(file: Uri): string { - return file.toString(true); - } -} - -export default class DiagnosticsManager { - - private readonly syntaxDiagnostics: DiagnosticSet; - private readonly semanticDiagnostics: DiagnosticSet; - private readonly currentDiagnostics: DiagnosticCollection; - private _validate: boolean = true; - - constructor( - language: string - ) { - this.syntaxDiagnostics = new DiagnosticSet(); - this.semanticDiagnostics = new DiagnosticSet(); - this.currentDiagnostics = languages.createDiagnosticCollection(language); - } - - public dispose() { - this.currentDiagnostics.dispose(); - } - - public reInitialize(): void { - this.currentDiagnostics.clear(); - this.syntaxDiagnostics.clear(); - this.semanticDiagnostics.clear(); - } - - public set validate(value: boolean) { - if (this._validate === value) { - return; - } - this._validate = value; - if (!value) { - this.currentDiagnostics.clear(); - } - } - - public syntaxDiagnosticsReceived(file: Uri, syntaxDiagnostics: Diagnostic[]): void { - this.syntaxDiagnostics.set(file, syntaxDiagnostics); - this.updateCurrentDiagnostics(file); - } - - public semanticDiagnosticsReceived(file: Uri, semanticDiagnostics: Diagnostic[]): void { - this.semanticDiagnostics.set(file, semanticDiagnostics); - this.updateCurrentDiagnostics(file); - } - - public configFileDiagnosticsReceived(file: Uri, diagnostics: Diagnostic[]): void { - this.currentDiagnostics.set(file, diagnostics); - } - - public delete(resource: Uri): void { - this.currentDiagnostics.delete(resource); - } - - private updateCurrentDiagnostics(file: Uri) { - if (!this._validate) { - return; - } - - const semanticDiagnostics = this.semanticDiagnostics.get(file); - const syntaxDiagnostics = this.syntaxDiagnostics.get(file); - this.currentDiagnostics.set(file, semanticDiagnostics.concat(syntaxDiagnostics)); - } - - public getDiagnostics(file: Uri): Diagnostic[] { - return this.currentDiagnostics.get(file) || []; - } -} \ No newline at end of file diff --git a/extensions/typescript/src/features/documentHighlightProvider.ts b/extensions/typescript/src/features/documentHighlightProvider.ts deleted file mode 100644 index d155f78f187..00000000000 --- a/extensions/typescript/src/features/documentHighlightProvider.ts +++ /dev/null @@ -1,53 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { DocumentHighlightProvider, DocumentHighlight, DocumentHighlightKind, TextDocument, Position, Range, CancellationToken } from 'vscode'; - -import { ITypeScriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; - -const stringDelimiters = ['"', '\'', '`']; - -export default class TypeScriptDocumentHighlightProvider implements DocumentHighlightProvider { - public constructor( - private client: ITypeScriptServiceClient - ) { } - - public async provideDocumentHighlights( - resource: TextDocument, - position: Position, - token: CancellationToken - ): Promise { - const filepath = this.client.normalizePath(resource.uri); - if (!filepath) { - return []; - } - - const args = vsPositionToTsFileLocation(filepath, position); - try { - const response = await this.client.execute('occurrences', args, token); - const data = response.body; - if (data && data.length) { - // Workaround for https://github.com/Microsoft/TypeScript/issues/12780 - // Don't highlight string occurrences - const firstOccurrence = data[0]; - if (this.client.apiVersion.has213Features() && firstOccurrence.start.offset > 1) { - // Check to see if contents around first occurrence are string delimiters - const contents = resource.getText(new Range(firstOccurrence.start.line - 1, firstOccurrence.start.offset - 1 - 1, firstOccurrence.end.line - 1, firstOccurrence.end.offset - 1 + 1)); - if (contents && contents.length > 2 && stringDelimiters.indexOf(contents[0]) >= 0 && contents[0] === contents[contents.length - 1]) { - return []; - } - } - return data.map(item => - new DocumentHighlight( - tsTextSpanToVsRange(item), - item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read)); - } - return []; - } catch { - return []; - } - } -} \ No newline at end of file diff --git a/extensions/typescript/src/utils/convert.ts b/extensions/typescript/src/utils/convert.ts deleted file mode 100644 index 299597f34d5..00000000000 --- a/extensions/typescript/src/utils/convert.ts +++ /dev/null @@ -1,30 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import * as Proto from '../protocol'; - - -export const tsTextSpanToVsRange = (span: Proto.TextSpan) => - new vscode.Range( - span.start.line - 1, span.start.offset - 1, - span.end.line - 1, span.end.offset - 1); - -export const tsLocationToVsPosition = (tslocation: Proto.Location) => - new vscode.Position(tslocation.line - 1, tslocation.offset - 1); - -export const vsPositionToTsFileLocation = (file: string, position: vscode.Position): Proto.FileLocationRequestArgs => ({ - file, - line: position.line + 1, - offset: position.character + 1 -}); - -export const vsRangeToTsFileRange = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ - file, - startLine: range.start.line + 1, - startOffset: range.start.character + 1, - endLine: range.end.line + 1, - endOffset: range.end.character + 1 -}); \ No newline at end of file diff --git a/extensions/typescript/src/utils/workspaceEdit.ts b/extensions/typescript/src/utils/workspaceEdit.ts deleted file mode 100644 index 4cb29eb8467..00000000000 --- a/extensions/typescript/src/utils/workspaceEdit.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import { ITypeScriptServiceClient } from '../typescriptService'; -import * as Proto from '../protocol'; -import { tsTextSpanToVsRange } from './convert'; - -export function createWorkspaceEditFromFileCodeEdits( - client: ITypeScriptServiceClient, - edits: Iterable -): vscode.WorkspaceEdit { - const workspaceEdit = new vscode.WorkspaceEdit(); - for (const edit of edits) { - for (const textChange of edit.textChanges) { - workspaceEdit.replace(client.asUrl(edit.fileName), - tsTextSpanToVsRange(textChange), - textChange.newText); - } - } - - return workspaceEdit; -} \ No newline at end of file diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 2a710ccda63..9775a3e7210 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,6 +2,6 @@ # yarn lockfile v1 -typescript@2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836" +typescript@2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624" diff --git a/package.json b/package.json index 34091a17f33..fd5f7ab7af6 100644 --- a/package.json +++ b/package.json @@ -43,11 +43,11 @@ "sudo-prompt": "^8.0.0", "v8-inspect-profiler": "^0.0.7", "vscode-chokidar": "1.6.2", - "vscode-debugprotocol": "1.27.0", + "vscode-debugprotocol": "1.28.0", "vscode-nsfw": "1.0.17", "vscode-ripgrep": "^0.8.1", - "vscode-textmate": "^3.3.1", - "vscode-xterm": "3.3.0-beta7", + "vscode-textmate": "^3.3.2", + "vscode-xterm": "3.3.0-beta8", "yauzl": "2.8.0" }, "devDependencies": { @@ -132,6 +132,6 @@ "optionalDependencies": { "windows-foreground-love": "0.1.0", "windows-mutex": "^0.2.0", - "windows-process-tree": "0.1.6" + "windows-process-tree": "0.2.0" } } diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 169e2e62a6c..00cf9b0ae3e 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -25,8 +25,8 @@ if %errorlevel% neq 0 exit /b %errorlevel% call .\scripts\test.bat --runGlob **\*.integrationTest.js %* if %errorlevel% neq 0 exit /b %errorlevel% -:: Tests in commonJS (language servers tests...) -call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\html-language-features\server\out\test\ +# Tests in commonJS (HTML, CSS, JSON language server tests...) +call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js if %errorlevel% neq 0 exit /b %errorlevel% rmdir /s /q %VSCODEUSERDATADIR% diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 0c31f048d5c..b7f242de9b5 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -23,7 +23,7 @@ rm -r $ROOT/extensions/emmet/test-fixtures # Integration tests in AMD ./scripts/test.sh --runGlob **/*.integrationTest.js "$@" -# Tests in commonJS (language server tests...) -./scripts/node-electron.sh ./node_modules/mocha/bin/_mocha ./extensions/html-language-features/server/out/test/ +# Tests in commonJS (HTML, CSS, JSON language server tests...) +./scripts/node-electron.sh ./node_modules/mocha/bin/_mocha ./extensions/*/server/out/test/ rm -r $VSCODEUSERDATADIR diff --git a/src/bootstrap.js b/src/bootstrap.js index 5d7c3bf61f5..707513f7235 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -11,10 +11,10 @@ const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar'; const originalResolveLookupPaths = Module._resolveLookupPaths; - Module._resolveLookupPaths = function (request, parent) { - const result = originalResolveLookupPaths(request, parent); + Module._resolveLookupPaths = function (request, parent, newReturn) { + const result = originalResolveLookupPaths(request, parent, newReturn); - const paths = result[1]; + const paths = newReturn ? result : result[1]; for (let i = 0, len = paths.length; i < len; i++) { if (paths[i] === NODE_MODULES_PATH) { paths.splice(i, 0, NODE_MODULES_ASAR_PATH); diff --git a/src/cli.js b/src/cli.js index a73ad05e861..db7b6cce206 100644 --- a/src/cli.js +++ b/src/cli.js @@ -11,10 +11,10 @@ const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar'; const originalResolveLookupPaths = Module._resolveLookupPaths; - Module._resolveLookupPaths = function (request, parent) { - const result = originalResolveLookupPaths(request, parent); + Module._resolveLookupPaths = function (request, parent, newReturn) { + const result = originalResolveLookupPaths(request, parent, newReturn); - const paths = result[1]; + const paths = newReturn ? result : result[1]; for (let i = 0, len = paths.length; i < len; i++) { if (paths[i] === NODE_MODULES_PATH) { paths.splice(i, 0, NODE_MODULES_ASAR_PATH); diff --git a/src/main.js b/src/main.js index 62a0363c172..84af1506598 100644 --- a/src/main.js +++ b/src/main.js @@ -20,10 +20,10 @@ Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https: const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar'; const originalResolveLookupPaths = Module._resolveLookupPaths; - Module._resolveLookupPaths = function (request, parent) { - const result = originalResolveLookupPaths(request, parent); + Module._resolveLookupPaths = function (request, parent, newReturn) { + const result = originalResolveLookupPaths(request, parent, newReturn); - const paths = result[1]; + const paths = newReturn ? result : result[1]; for (let i = 0, len = paths.length; i < len; i++) { if (paths[i] === NODE_MODULES_PATH) { paths.splice(i, 0, NODE_MODULES_ASAR_PATH); @@ -280,14 +280,14 @@ function getNLSConfiguration(locale) { return undefined; } - let isCoreLangaguage = true; + let isCoreLanguage = true; if (locale) { - isCoreLangaguage = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-cn', 'zh-tw'].some((language) => { + isCoreLanguage = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-cn', 'zh-tw'].some((language) => { return locale === language || locale.startsWith(language + '-'); }); } - if (isCoreLangaguage) { + if (isCoreLanguage) { return Promise.resolve(resolveLocale(locale)); } else { perf.mark('nlsGeneration:start'); diff --git a/src/typings/vscode-xterm.d.ts b/src/typings/vscode-xterm.d.ts index bae79db7568..2bbcfac4f8f 100644 --- a/src/typings/vscode-xterm.d.ts +++ b/src/typings/vscode-xterm.d.ts @@ -17,6 +17,13 @@ declare module 'vscode-xterm' { * An object containing start up options for the terminal. */ export interface ITerminalOptions { + /** + * Whether background should support non-opaque color. It must be set before + * executing open() method and can't be changed later without excuting it again. + * Warning: Enabling this option can reduce performances somewhat. + */ + allowTransparency?: boolean; + /** * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). */ @@ -49,6 +56,8 @@ declare module 'vscode-xterm' { /** * Whether to enable the rendering of bold text. + * + * @deprecated Use fontWeight and fontWeightBold instead. */ enableBold?: boolean; @@ -181,8 +190,8 @@ declare module 'vscode-xterm' { matchIndex?: number; /** - * A callback that validates an individual link, returning true if valid and - * false if invalid. + * A callback that validates whether to create an individual link, pass + * whether the link is valid to the callback. */ validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; @@ -227,6 +236,12 @@ declare module 'vscode-xterm' { dispose(): void; } + export interface IMarker extends IDisposable { + readonly id: number; + readonly isDisposed: boolean; + readonly line: number; + } + export interface ILocalizableStrings { blankLine: string; promptLabel: string; @@ -236,7 +251,7 @@ declare module 'vscode-xterm' { /** * The class that represents an xterm.js terminal. */ - export class Terminal { + export class Terminal implements IEventEmitter { /** * The element containing the terminal. */ @@ -257,6 +272,12 @@ declare module 'vscode-xterm' { */ cols: number; + /** + * (EXPERIMENTAL) Get all markers registered against the buffer. If the alt + * buffer is active this will always return []. + */ + markers: IMarker[]; + /** * Natural language strings that can be localized. */ @@ -290,7 +311,7 @@ declare module 'vscode-xterm' { * @param type The type of the event. * @param listener The listener. */ - on(type: 'data', listener: (data?: string) => void): void; + on(type: 'data', listener: (...args: any[]) => void): void; /** * Registers an event listener. * @param type The type of the event. @@ -341,6 +362,10 @@ declare module 'vscode-xterm' { */ off(type: 'blur' | 'focus' | 'linefeed' | 'selection' | 'data' | 'key' | 'keypress' | 'keydown' | 'refresh' | 'resize' | 'scroll' | 'title' | string, listener: (...args: any[]) => void): void; + emit(type: string, data?: any): void; + + addDisposableListener(type: string, handler: (...args: any[]) => void): IDisposable; + /** * Resizes the terminal. * @param x The number of columns to resize to. @@ -383,7 +408,7 @@ declare module 'vscode-xterm' { * @param options Options for the link matcher. * @return The ID of the new matcher, this can be used to deregister. */ - registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => boolean | void, options?: ILinkMatcherOptions): number; + registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number; /** * (EXPERIMENTAL) Deregisters a link matcher if it has been registered. @@ -391,6 +416,13 @@ declare module 'vscode-xterm' { */ deregisterLinkMatcher(matcherId: number): void; + /** + * (EXPERIMENTAL) Adds a marker to the normal buffer and returns it. If the + * alt buffer is active, undefined is returned. + * @param cursorYOffset The y position offset of the marker from the cursor. + */ + addMarker(cursorYOffset: number): IMarker; + /** * Gets whether the terminal has an active selection. */ @@ -412,21 +444,12 @@ declare module 'vscode-xterm' { */ selectAll(): void; - // /** - // * Find the next instance of the term, then scroll to and select it. If it - // * doesn't exist, do nothing. - // * @param term Tne search term. - // * @return Whether a result was found. - // */ - // findNext(term: string): boolean; - - // /** - // * Find the previous instance of the term, then scroll to and select it. If it - // * doesn't exist, do nothing. - // * @param term Tne search term. - // * @return Whether a result was found. - // */ - // findPrevious(term: string): boolean; + /** + * Selects text in the buffer between 2 lines. + * @param start The 0-based line index to select from (inclusive). + * @param end The 0-based line index to select to (inclusive). + */ + selectLines(start: number, end: number): void; /** * Destroys the terminal and detaches it from the DOM. @@ -455,6 +478,12 @@ declare module 'vscode-xterm' { */ scrollToBottom(): void; + /** + * Scrolls to a line within the buffer. + * @param line The 0-based line index to scroll to. + */ + scrollToLine(line: number): void; + /** * Clear the entire buffer, making the prompt line the new first line. */ @@ -470,7 +499,7 @@ declare module 'vscode-xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'termName'): string; + getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'termName'): string; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -503,6 +532,12 @@ declare module 'vscode-xterm' { * @param value The option value. */ setOption(key: 'fontFamily' | 'termName' | 'bellSound', value: string): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void; /** * Sets an option on the terminal. * @param key The option key. @@ -545,6 +580,12 @@ declare module 'vscode-xterm' { * @param value The option value. */ setOption(key: 'theme', value: ITheme): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'cols' | 'rows', value: number): void; /** * Sets an option on the terminal. * @param key The option key. @@ -578,10 +619,10 @@ declare module 'vscode-xterm' { declare module 'vscode-xterm' { interface Terminal { buffer: { - /** - * The viewport position. - */ + y: number; + ybase: number; ydisp: number; + x: number; }; /** diff --git a/src/typings/windows-process-tree.d.ts b/src/typings/windows-process-tree.d.ts index aec2670a5cd..b9db4ea76a8 100644 --- a/src/typings/windows-process-tree.d.ts +++ b/src/typings/windows-process-tree.d.ts @@ -4,13 +4,60 @@ *--------------------------------------------------------------------------------------------*/ declare module 'windows-process-tree' { - interface ProcessTreeNode { - pid: number, - name: string, - children: ProcessTreeNode[] + export enum ProcessDataFlag { + None = 0, + Memory = 1, + CommandLine = 2 } - function get(rootPid: number, callback: (tree: ProcessTreeNode) => void): void; + export interface IProcessInfo { + pid: number; + ppid: number; + name: string; - export = get; + /** + * The working set size of the process, in bytes. + */ + memory?: number; + + /** + * The string returned is at most 512 chars, strings exceeding this length are truncated. + */ + commandLine?: string; + } + + export interface IProcessCpuInfo extends IProcessInfo { + cpu?: number; + } + + export interface IProcessTreeNode { + pid: number; + name: string; + memory?: number; + commandLine?: string; + children: IProcessTreeNode[]; + } + + /** + * Returns a tree of processes with the rootPid process as the root. + * @param rootPid - The pid of the process that will be the root of the tree. + * @param callback - The callback to use with the returned list of processes. + * @param flags - The flags for what process data should be included. + */ + export function getProcessTree(rootPid: number, callback: (tree: IProcessTreeNode) => void, flags?: ProcessDataFlag): void; + + /** + * Returns a list of processes containing the rootPid process and all of its descendants. + * @param rootPid - The pid of the process of interest. + * @param callback - The callback to use with the returned set of processes. + * @param flags - The flags for what process data should be included. + */ + export function getProcessList(rootPid: number, callback: (processList: IProcessInfo[]) => void, flags?: ProcessDataFlag): void; + + /** + * Returns the list of processes annotated with cpu usage information. + * @param processList - The list of processes. + * @param callback - The callback to use with the returned list of processes. + */ + export function getProcessCpuUsage(processList: IProcessInfo[], callback: (processListWithCpu: IProcessCpuInfo[]) => void): void; } diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index b3f1bce162d..a31eec3902b 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -12,8 +12,9 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event as BaseEvent, Emitter } from 'vs/base/common/event'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Gesture, EventType } from 'vs/base/browser/touch'; export interface IButtonOptions extends IButtonStyles { title?: boolean; @@ -43,7 +44,7 @@ export class Button { private buttonBorder: Color; private _onDidClick = new Emitter(); - readonly onDidClick: Event = this._onDidClick.event; + readonly onDidClick: BaseEvent = this._onDidClick.event; private focusTracker: DOM.IFocusTracker; @@ -63,7 +64,9 @@ export class Button { 'role': 'button' }).appendTo(container); - this.$el.on(DOM.EventType.CLICK, e => { + Gesture.addTarget(this.$el.getHTMLElement()); + + this.$el.on([DOM.EventType.CLICK, EventType.Tap], e => { if (!this.enabled) { DOM.EventHelper.stop(e); return; diff --git a/src/vs/base/browser/ui/countBadge/countBadge.ts b/src/vs/base/browser/ui/countBadge/countBadge.ts index 8ff58693925..6eb64da57bd 100644 --- a/src/vs/base/browser/ui/countBadge/countBadge.ts +++ b/src/vs/base/browser/ui/countBadge/countBadge.ts @@ -13,6 +13,7 @@ import { mixin } from 'vs/base/common/objects'; export interface ICountBadgeOptions extends ICountBadgetyles { count?: number; + countFormat?: string; titleFormat?: string; } @@ -31,6 +32,7 @@ export class CountBadge { private element: HTMLElement; private count: number; + private countFormat: string; private titleFormat: string; private badgeBackground: Color; @@ -48,6 +50,7 @@ export class CountBadge { this.badgeBorder = this.options.badgeBorder; this.element = append(container, $('.monaco-count-badge')); + this.countFormat = this.options.countFormat || '{0}'; this.titleFormat = this.options.titleFormat || ''; this.setCount(this.options.count || 0); } @@ -57,13 +60,18 @@ export class CountBadge { this.render(); } + setCountFormat(countFormat: string) { + this.countFormat = countFormat; + this.render(); + } + setTitleFormat(titleFormat: string) { this.titleFormat = titleFormat; this.render(); } private render() { - this.element.textContent = '' + this.count; + this.element.textContent = format(this.countFormat, this.count); this.element.title = format(this.titleFormat, this.count); this.applyStyles(); diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index d0931e27a1c..83a76cd7330 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -360,19 +360,22 @@ export class ListView implements ISpliceable, IDisposable { private toMouseEvent(browserEvent: MouseEvent): IListMouseEvent { const index = this.getItemIndexFromEventTarget(browserEvent.target); - const element = index < 0 ? undefined : this.items[index].element; + const item = index < 0 ? undefined : this.items[index]; + const element = item && item.element; return { browserEvent, index, element }; } private toTouchEvent(browserEvent: TouchEvent): IListTouchEvent { const index = this.getItemIndexFromEventTarget(browserEvent.target); - const element = index < 0 ? undefined : this.items[index].element; + const item = index < 0 ? undefined : this.items[index]; + const element = item && item.element; return { browserEvent, index, element }; } private toGestureEvent(browserEvent: GestureEvent): IListGestureEvent { const index = this.getItemIndexFromEventTarget(browserEvent.initialTarget); - const element = index < 0 ? undefined : this.items[index].element; + const item = index < 0 ? undefined : this.items[index]; + const element = item && item.element; return { browserEvent, index, element }; } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index edbc42e9a0a..a93a19f2be3 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -142,7 +142,7 @@ class Trait implements ISpliceable, IDisposable { const end = start + deleteCount; const indexes = [ ...this.indexes.filter(i => i < start), - ...elements.reduce((r, hasTrait, i) => hasTrait ? [...r, i + start] : r, []), + ...elements.map((hasTrait, i) => hasTrait ? i + start : -1).filter(i => i !== -1), ...this.indexes.filter(i => i >= end).map(i => i + diff) ]; @@ -388,7 +388,7 @@ const DefaultMultipleSelectionContoller = { isSelectionRangeChangeEvent }; -const DefaultOpenController = { +const DefaultOpenController: IOpenController = { shouldOpen: (event: UIEvent) => { if (event instanceof MouseEvent) { return !isMouseRightClick(event); @@ -396,7 +396,7 @@ const DefaultOpenController = { return true; } -} as IOpenController; +}; class MouseController implements IDisposable { @@ -852,9 +852,7 @@ export class List implements ISpliceable, IDisposable { readonly onContextMenu: Event> = Event.None; private _onOpen = new Emitter>(); - @memoize get onOpen(): Event> { - return this._onOpen.event; - } + readonly onOpen: Event> = this._onOpen.event; private _onPin = new Emitter(); @memoize get onPin(): Event> { diff --git a/src/vs/base/browser/ui/sash/sash.css b/src/vs/base/browser/ui/sash/sash.css index 0c733246563..91888dd1e9e 100644 --- a/src/vs/base/browser/ui/sash/sash.css +++ b/src/vs/base/browser/ui/sash/sash.css @@ -25,22 +25,12 @@ cursor: default !important; } -.vertical-cursor-container { - cursor: ew-resize; -} - -.horizontal-cursor-container { - cursor: ns-resize; -} - /** Custom Mac Cursor */ -.monaco-sash.mac.vertical, -.vertical-cursor-container-mac { +.monaco-sash.mac.vertical { cursor: col-resize; } -.monaco-sash.mac.horizontal, -.horizontal-cursor-container-mac { +.monaco-sash.mac.horizontal { cursor: row-resize; } \ No newline at end of file diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index a20fac5fd15..44701f7b59e 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -138,12 +138,12 @@ export class Sash { iframes.style('pointer-events', 'none'); // disable mouse events on iframes as long as we drag the sash } - let mouseDownEvent = new StandardMouseEvent(e); - let startX = mouseDownEvent.posx; - let startY = mouseDownEvent.posy; + const mouseDownEvent = new StandardMouseEvent(e); + const startX = mouseDownEvent.posx; + const startY = mouseDownEvent.posy; const altKey = mouseDownEvent.altKey; - let startEvent: ISashEvent = { + const startEvent: ISashEvent = { startX: startX, currentX: startX, startY: startY, @@ -154,14 +154,21 @@ export class Sash { this.$e.addClass('active'); this._onDidStart.fire(startEvent); - let $window = $(window); - let containerCSSClass = `${this.getOrientation()}-cursor-container${isMacintosh ? '-mac' : ''}`; + const $window = $(window); + + // fix https://github.com/Microsoft/vscode/issues/21675 + const globalStyle = DOM.createStyleSheet(this.$e.getHTMLElement()); + if (this.orientation === Orientation.HORIZONTAL) { + globalStyle.innerHTML = `* { cursor: ${isMacintosh ? 'row-resize' : 'ns-resize'}; }`; + } else { + globalStyle.innerHTML = `* { cursor: ${isMacintosh ? 'col-resize' : 'ew-resize'}; }`; + } $window.on('mousemove', (e) => { DOM.EventHelper.stop(e, false); - let mouseMoveEvent = new StandardMouseEvent(e as MouseEvent); + const mouseMoveEvent = new StandardMouseEvent(e as MouseEvent); - let event: ISashEvent = { + const event: ISashEvent = { startX: startX, currentX: mouseMoveEvent.posx, startY: startY, @@ -172,28 +179,28 @@ export class Sash { this._onDidChange.fire(event); }).once('mouseup', (e) => { DOM.EventHelper.stop(e, false); + + this.$e.getHTMLElement().removeChild(globalStyle); + this.$e.removeClass('active'); this._onDidEnd.fire(); $window.off('mousemove'); - document.body.classList.remove(containerCSSClass); const iframes = $(DOM.getElementsByTagName('iframe')); if (iframes) { iframes.style('pointer-events', 'auto'); } }); - - document.body.classList.add(containerCSSClass); } private onTouchStart(event: GestureEvent): void { DOM.EventHelper.stop(event); - let listeners: IDisposable[] = []; + const listeners: IDisposable[] = []; - let startX = event.pageX; - let startY = event.pageY; + const startX = event.pageX; + const startY = event.pageY; const altKey = event.altKey; @@ -227,7 +234,7 @@ export class Sash { let style: { top?: string; left?: string; height?: string; width?: string; }; if (this.orientation === Orientation.VERTICAL) { - let verticalProvider = (this.layoutProvider); + const verticalProvider = (this.layoutProvider); style = { left: verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px' }; if (verticalProvider.getVerticalSashTop) { @@ -238,7 +245,7 @@ export class Sash { style.height = verticalProvider.getVerticalSashHeight(this) + 'px'; } } else { - let horizontalProvider = (this.layoutProvider); + const horizontalProvider = (this.layoutProvider); style = { top: horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px' }; if (horizontalProvider.getHorizontalSashLeft) { @@ -357,9 +364,9 @@ export class VSash extends Disposable implements IVerticalSashLayoutProvider { } private computeSashPosition(sashRatio: number = this.ratio) { - let contentWidth = this.dimension.width; + const contentWidth = this.dimension.width; let sashPosition = Math.floor((sashRatio || 0.5) * contentWidth); - let midPoint = Math.floor(0.5 * contentWidth); + const midPoint = Math.floor(0.5 * contentWidth); if (contentWidth > this.minWidth * 2) { if (sashPosition < this.minWidth) { diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index c2434674bfc..5aafe0bd8a0 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -336,16 +336,6 @@ export abstract class AbstractScrollableElement extends Widget { deltaY = 0; } - if (Platform.isMacintosh) { - // Give preference to vertical scrolling - if (deltaY && Math.abs(deltaX) < 0.2) { - deltaX = 0; - } - if (Math.abs(deltaY) > Math.abs(deltaX) * 0.5) { - deltaX = 0; - } - } - const futureScrollPosition = this._scrollable.getFutureScrollPosition(); let desiredScrollPosition: INewScrollPosition = {}; diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 084dc7d2a56..286bfeb835f 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -61,6 +61,9 @@ class SelectListRenderer implements IRendererdata.root), 'option-disabled'); + } else { + // Make sure we do class removal from prior template rendering + dom.removeClass((data.root), 'option-disabled'); } } diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 98bf603fc47..dd2a37bb9af 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -29,10 +29,13 @@ export function asWinJsPromise(callback: (token: CancellationToken) => T | TP return new TPromise((resolve, reject, progress) => { let item = callback(source.token); if (item instanceof TPromise) { + always(item, () => source.dispose()); item.then(resolve, reject, progress); } else if (isThenable(item)) { + always(item, () => source.dispose()); item.then(resolve, reject); } else { + source.dispose(); resolve(item); } }, () => { @@ -320,6 +323,10 @@ export function timeout(n: number): Promise { return new Promise(resolve => setTimeout(resolve, n)); } +function isWinJSPromise(candidate: any): candidate is TPromise { + return TPromise.is(candidate) && typeof (candidate).done === 'function'; +} + /** * Returns a new promise that joins the provided promise. Upon completion of * the provided promise the provided function will always be called. This @@ -327,28 +334,37 @@ export function timeout(n: number): Promise { * @param promise a promise * @param f a function that will be call in the success and error case. */ -export function always(promise: TPromise, f: Function): TPromise { - return new TPromise((c, e, p) => { - promise.done((result) => { - try { - f(result); - } catch (e1) { - errors.onUnexpectedError(e1); - } - c(result); - }, (err) => { - try { - f(err); - } catch (e1) { - errors.onUnexpectedError(e1); - } - e(err); - }, (progress) => { - p(progress); +export function always(thenable: TPromise, f: Function): TPromise; +export function always(promise: Thenable, f: Function): Thenable; +export function always(winjsPromiseOrThenable: Thenable | TPromise, f: Function): TPromise | Thenable { + if (isWinJSPromise(winjsPromiseOrThenable)) { + return new TPromise((c, e, p) => { + winjsPromiseOrThenable.done((result) => { + try { + f(result); + } catch (e1) { + errors.onUnexpectedError(e1); + } + c(result); + }, (err) => { + try { + f(err); + } catch (e1) { + errors.onUnexpectedError(e1); + } + e(err); + }, (progress) => { + p(progress); + }); + }, () => { + winjsPromiseOrThenable.cancel(); }); - }, () => { - promise.cancel(); - }); + + } else { + // simple + winjsPromiseOrThenable.then(_ => f(), _ => f()); + return winjsPromiseOrThenable; + } } /** diff --git a/src/vs/base/common/cancellation.ts b/src/vs/base/common/cancellation.ts index 6797298bd8b..e132d57e5e8 100644 --- a/src/vs/base/common/cancellation.ts +++ b/src/vs/base/common/cancellation.ts @@ -45,8 +45,7 @@ class MutableToken implements CancellationToken { this._isCancelled = true; if (this._emitter) { this._emitter.fire(undefined); - this._emitter.dispose(); - this._emitter = undefined; + this.dispose(); } } } @@ -64,6 +63,13 @@ class MutableToken implements CancellationToken { } return this._emitter.event; } + + public dispose(): void { + if (this._emitter) { + this._emitter.dispose(); + this._emitter = undefined; + } + } } export class CancellationTokenSource { @@ -93,6 +99,13 @@ export class CancellationTokenSource { } dispose(): void { - this.cancel(); + if (!this._token) { + // ensure to initialize with an empty token if we had none + this._token = CancellationToken.None; + + } else if (this._token instanceof MutableToken) { + // actually dispose + this._token.dispose(); + } } } diff --git a/src/vs/base/common/decorators.ts b/src/vs/base/common/decorators.ts index 8f7578c29fc..719407fe245 100644 --- a/src/vs/base/common/decorators.ts +++ b/src/vs/base/common/decorators.ts @@ -33,6 +33,10 @@ export function memoize(target: any, key: string, descriptor: any) { if (typeof descriptor.value === 'function') { fnKey = 'value'; fn = descriptor.value; + + if (fn.length !== 0) { + console.warn('Memoize should only be used in functions with zero parameters'); + } } else if (typeof descriptor.get === 'function') { fnKey = 'get'; fn = descriptor.get; @@ -58,13 +62,27 @@ export function memoize(target: any, key: string, descriptor: any) { }; } -export function debounce(delay: number): Function { +export interface IDebouceReducer { + (previousValue: T, ...args: any[]): T; +} + +export function debounce(delay: number, reducer?: IDebouceReducer, initialValueProvider?: () => T): Function { return createDecorator((fn, key) => { const timerKey = `$debounce$${key}`; + let result = initialValueProvider ? initialValueProvider() : void 0; return function (this: any, ...args: any[]) { clearTimeout(this[timerKey]); - this[timerKey] = setTimeout(() => fn.apply(this, args), delay); + + if (reducer) { + result = reducer(result, ...args); + args = [result]; + } + + this[timerKey] = setTimeout(() => { + fn.apply(this, args); + result = initialValueProvider ? initialValueProvider() : void 0; + }, delay); }; }); } \ No newline at end of file diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index d1f4b3a114b..2ac42d2fa4e 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -365,6 +365,7 @@ export interface IChainableEvent { map(fn: (i: T) => O): IChainableEvent; forEach(fn: (i: T) => void): IChainableEvent; filter(fn: (e: T) => boolean): IChainableEvent; + latch(): IChainableEvent; on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; } @@ -398,6 +399,10 @@ class ChainableEvent implements IChainableEvent { return new ChainableEvent(filterEvent(this._event, fn)); } + latch(): IChainableEvent { + return new ChainableEvent(latch(this._event)); + } + on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) { return this._event(listener, thisArgs, disposables); } @@ -534,3 +539,15 @@ export function fromNodeEventEmitter(emitter: NodeEventEmitter, eventName: st return result.event; } + +export function latch(event: Event): Event { + let firstCall = true; + let cache: T; + + return filterEvent(event, value => { + let shouldEmit = firstCall || value !== cache; + firstCall = false; + cache = value; + return shouldEmit; + }); +} \ No newline at end of file diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 9c7dc2dc68d..b268681d0c3 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -50,7 +50,7 @@ function _matchesPrefix(ignoreCase: boolean, word: string, wordToMatchAgainst: s let matches: boolean; if (ignoreCase) { - matches = strings.beginsWithIgnoreCase(wordToMatchAgainst, word); + matches = strings.startsWithIgnoreCase(wordToMatchAgainst, word); } else { matches = wordToMatchAgainst.indexOf(word) === 0; } diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index ce7439790af..ade3020fcdc 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -5,10 +5,10 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import * as platform from 'vs/base/common/platform'; -import { nativeSep, normalize, isEqualOrParent, isEqual, basename as pathsBasename, join } from 'vs/base/common/paths'; -import { endsWith, ltrim } from 'vs/base/common/strings'; +import { nativeSep, normalize, basename as pathsBasename, join, sep } from 'vs/base/common/paths'; +import { endsWith, ltrim, equalsIgnoreCase, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; +import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform'; export interface IWorkspaceFolderProvider { getWorkspaceFolder(resource: URI): { uri: URI }; @@ -30,6 +30,7 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo resource = URI.file(resource); } + // return early if the resource is neither file:// nor untitled:// if (resource.scheme !== Schemas.file && resource.scheme !== Schemas.untitled) { return resource.with({ query: null, fragment: null }).toString(true); } @@ -40,7 +41,7 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo const hasMultipleRoots = rootProvider.getWorkspace().folders.length > 1; let pathLabel: string; - if (isEqual(baseResource.uri.fsPath, resource.fsPath, !platform.isLinux /* ignorecase */)) { + if (isLinux ? baseResource.uri.fsPath === resource.fsPath : equalsIgnoreCase(baseResource.uri.fsPath, resource.fsPath)) { pathLabel = ''; // no label if pathes are identical } else { pathLabel = normalize(ltrim(resource.fsPath.substr(baseResource.uri.fsPath.length), nativeSep), true); @@ -61,7 +62,7 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo // normalize and tildify (macOS, Linux only) let res = normalize(resource.fsPath, true); - if (!platform.isWindows && userHomeProvider) { + if (!isWindows && userHomeProvider) { res = tildify(res, userHomeProvider.userHome); } @@ -88,7 +89,7 @@ export function getBaseLabel(resource: URI | string): string { } function hasDriveLetter(path: string): boolean { - return platform.isWindows && path && path[1] === ':'; + return isWindows && path && path[1] === ':'; } export function normalizeDriveLetter(path: string): string { @@ -99,9 +100,22 @@ export function normalizeDriveLetter(path: string): string { return path; } +let normalizedUserHomeCached: { original: string; normalized: string } = Object.create(null); export function tildify(path: string, userHome: string): string { - if (path && (platform.isMacintosh || platform.isLinux) && isEqualOrParent(path, userHome, !platform.isLinux /* ignorecase */)) { - path = `~${path.substr(userHome.length)}`; + if (isWindows || !path || !userHome) { + return path; // unsupported + } + + // Keep a normalized user home path as cache to prevent accumulated string creation + let normalizedUserHome = normalizedUserHomeCached.original === userHome ? normalizedUserHomeCached.normalized : void 0; + if (!normalizedUserHome) { + normalizedUserHome = `${rtrim(userHome, sep)}${sep}`; + normalizedUserHomeCached = { original: userHome, normalized: normalizedUserHome }; + } + + // Linux: case sensitive, macOS: case insensitive + if (isLinux ? startsWith(path, normalizedUserHome) : startsWithIgnoreCase(path, normalizedUserHome)) { + path = `~/${path.substr(normalizedUserHome.length)}`; } return path; @@ -340,7 +354,7 @@ export function template(template: string, values: { [key: string]: string | ISe * - macOS: Unsupported (replace && with empty string) */ export function mnemonicMenuLabel(label: string, forceDisableMnemonics?: boolean): string { - if (platform.isMacintosh || forceDisableMnemonics) { + if (isMacintosh || forceDisableMnemonics) { return label.replace(/\(&&\w\)|&&/g, ''); } @@ -354,11 +368,11 @@ export function mnemonicMenuLabel(label: string, forceDisableMnemonics?: boolean * - macOS: Unsupported (replace && with empty string) */ export function mnemonicButtonLabel(label: string): string { - if (platform.isMacintosh) { + if (isMacintosh) { return label.replace(/\(&&\w\)|&&/g, ''); } - return label.replace(/&&/g, platform.isWindows ? '&' : '_'); + return label.replace(/&&/g, isWindows ? '&' : '_'); } export function unmnemonicLabel(label: string): string { diff --git a/src/vs/base/common/marked/OSSREADME.json b/src/vs/base/common/marked/OSSREADME.json index 010e42bd7b8..42d526944b9 100644 --- a/src/vs/base/common/marked/OSSREADME.json +++ b/src/vs/base/common/marked/OSSREADME.json @@ -3,6 +3,6 @@ [{ "name": "chjj-marked", "repositoryURL": "https://github.com/npmcomponent/chjj-marked", - "version": "0.3.12", + "version": "0.3.18", "license": "MIT" }] diff --git a/src/vs/base/common/marked/marked.js b/src/vs/base/common/marked/marked.js index 11d29ced080..ca72ea8d6dc 100644 --- a/src/vs/base/common/marked/marked.js +++ b/src/vs/base/common/marked/marked.js @@ -1,12 +1,13 @@ /** * marked - a markdown parser * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) - * https://github.com/chjj/marked + * https://github.com/markedjs/marked */ var __marked_exports; -(function() { +;(function(root) { +'use strict'; /** * Block-Level Grammar @@ -31,45 +32,45 @@ var block = { block._label = /(?:\\[\[\]]|[^\[\]])+/; block._title = /(?:"(?:\\"|[^"]|"[^"\n]*")*"|'\n?(?:[^'\n]+\n?)*'|\([^()]*\))/; -block.def = replace(block.def) - ('label', block._label) - ('title', block._title) - (); +block.def = edit(block.def) + .replace('label', block._label) + .replace('title', block._title) + .getRegex(); block.bullet = /(?:[*+-]|\d+\.)/; block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; -block.item = replace(block.item, 'gm') - (/bull/g, block.bullet) - (); +block.item = edit(block.item, 'gm') + .replace(/bull/g, block.bullet) + .getRegex(); -block.list = replace(block.list) - (/bull/g, block.bullet) - ('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))') - ('def', '\\n+(?=' + block.def.source + ')') - (); +block.list = edit(block.list) + .replace(/bull/g, block.bullet) + .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))') + .replace('def', '\\n+(?=' + block.def.source + ')') + .getRegex(); block._tag = '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b'; -block.html = replace(block.html) - ('comment', //) - ('closed', /<(tag)[\s\S]+?<\/\1>/) - ('closing', /]*)*?\/?>/) - (/tag/g, block._tag) - (); +block.html = edit(block.html) + .replace('comment', //) + .replace('closed', /<(tag)[\s\S]+?<\/\1>/) + .replace('closing', /\s]*)*?\/?>/) + .replace(/tag/g, block._tag) + .getRegex(); -block.paragraph = replace(block.paragraph) - ('hr', block.hr) - ('heading', block.heading) - ('lheading', block.lheading) - ('tag', '<' + block._tag) - (); +block.paragraph = edit(block.paragraph) + .replace('hr', block.hr) + .replace('heading', block.heading) + .replace('lheading', block.lheading) + .replace('tag', '<' + block._tag) + .getRegex(); -block.blockquote = replace(block.blockquote) - ('paragraph', block.paragraph) - (); +block.blockquote = edit(block.blockquote) + .replace('paragraph', block.paragraph) + .getRegex(); /** * Normal Block Grammar @@ -87,11 +88,11 @@ block.gfm = merge({}, block.normal, { heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/ }); -block.gfm.paragraph = replace(block.paragraph) - ('(?!', '(?!' - + block.gfm.fences.source.replace('\\1', '\\2') + '|' - + block.list.source.replace('\\1', '\\3') + '|') - (); +block.gfm.paragraph = edit(block.paragraph) + .replace('(?!', '(?!' + + block.gfm.fences.source.replace('\\1', '\\2') + '|' + + block.list.source.replace('\\1', '\\3') + '|') + .getRegex(); /** * GFM + Tables Block Grammar @@ -131,7 +132,7 @@ Lexer.rules = block; * Static Lex Method */ -Lexer.lex = function (src, options) { +Lexer.lex = function(src, options) { var lexer = new Lexer(options); return lexer.lex(src); }; @@ -140,7 +141,7 @@ Lexer.lex = function (src, options) { * Preprocessing */ -Lexer.prototype.lex = function (src) { +Lexer.prototype.lex = function(src) { src = src .replace(/\r\n|\r/g, '\n') .replace(/\t/g, ' ') @@ -154,18 +155,19 @@ Lexer.prototype.lex = function (src) { * Lexing */ -Lexer.prototype.token = function (src, top) { - var src = src.replace(/^ +$/gm, '') - , next - , loose - , cap - , bull - , b - , item - , space - , i - , tag - , l; +Lexer.prototype.token = function(src, top) { + src = src.replace(/^ +$/gm, ''); + var next, + loose, + cap, + bull, + b, + item, + space, + i, + tag, + l, + isordered; while (src) { // newline @@ -280,10 +282,12 @@ Lexer.prototype.token = function (src, top) { if (cap = this.rules.list.exec(src)) { src = src.substring(cap[0].length); bull = cap[2]; + isordered = bull.length > 1; this.tokens.push({ type: 'list_start', - ordered: bull.length > 1 + ordered: isordered, + start: isordered ? +bull : '' }); // Get each top-level item. @@ -447,8 +451,7 @@ Lexer.prototype.token = function (src, top) { } if (src) { - throw new - Error('Infinite loop on byte: ' + src.charCodeAt(0)); + throw new Error('Infinite loop on byte: ' + src.charCodeAt(0)); } } @@ -463,13 +466,13 @@ var inline = { escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/, url: noop, - tag: /^|^<\/?[a-zA-Z0-9\-]+(?:"[^"]*"|'[^']*'|\s[^<'">\/]*)*?\/?>/, + tag: /^|^<\/?[a-zA-Z0-9\-]+(?:"[^"]*"|'[^']*'|\s[^<'">\/\s]*)*?\/?>/, link: /^!?\[(inside)\]\(href\)/, reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, - nolink: /^!?\[((?:\[[^\]]*\]|\\[\[\]]|[^\[\]])*)\]/, + nolink: /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\]/, strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, em: /^_([^\s_](?:[^_]|__)+?[^\s_])_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)/, - code: /^(`+)(\s*)([\s\S]*?[^`]?)\2\1(?!`)/, + code: /^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/, br: /^ {2,}\n(?!\s*$)/, del: noop, text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; -inline.link = replace(inline.link) - ('inside', inline._inside) - ('href', inline._href) - (); +inline.link = edit(inline.link) + .replace('inside', inline._inside) + .replace('href', inline._href) + .getRegex(); -inline.reflink = replace(inline.reflink) - ('inside', inline._inside) - (); +inline.reflink = edit(inline.reflink) + .replace('inside', inline._inside) + .getRegex(); /** * Normal Inline Grammar @@ -515,16 +518,16 @@ inline.pedantic = merge({}, inline.normal, { */ inline.gfm = merge({}, inline.normal, { - escape: replace(inline.escape)('])', '~|])')(), - url: replace(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/) - ('email', inline._email) - (), + escape: edit(inline.escape).replace('])', '~|])').getRegex(), + url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/) + .replace('email', inline._email) + .getRegex(), _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/, del: /^~~(?=\S)([\s\S]*?\S)~~/, - text: replace(inline.text) - (']|', '~]|') - ('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|') - () + text: edit(inline.text) + .replace(']|', '~]|') + .replace('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|') + .getRegex() }); /** @@ -532,8 +535,8 @@ inline.gfm = merge({}, inline.normal, { */ inline.breaks = merge({}, inline.gfm, { - br: replace(inline.br)('{2,}', '*')(), - text: replace(inline.gfm.text)('{2,}', '*')() + br: edit(inline.br).replace('{2,}', '*').getRegex(), + text: edit(inline.gfm.text).replace('{2,}', '*').getRegex() }); /** @@ -544,12 +547,11 @@ function InlineLexer(links, options) { this.options = options || marked.defaults; this.links = links; this.rules = inline.normal; - this.renderer = this.options.renderer || new Renderer; + this.renderer = this.options.renderer || new Renderer(); this.renderer.options = this.options; if (!this.links) { - throw new - Error('Tokens array requires a `links` property.'); + throw new Error('Tokens array requires a `links` property.'); } if (this.options.gfm) { @@ -573,7 +575,7 @@ InlineLexer.rules = inline; * Static Lexing/Compiling Method */ -InlineLexer.output = function (src, links, options) { +InlineLexer.output = function(src, links, options) { var inline = new InlineLexer(links, options); return inline.output(src); }; @@ -582,12 +584,12 @@ InlineLexer.output = function (src, links, options) { * Lexing/Compiling */ -InlineLexer.prototype.output = function (src) { - var out = '' - , link - , text - , href - , cap; +InlineLexer.prototype.output = function(src) { + var out = '', + link, + text, + href, + cap; while (src) { // escape @@ -660,7 +662,7 @@ InlineLexer.prototype.output = function (src) { // reflink, nolink if ((cap = this.rules.reflink.exec(src)) - || (cap = this.rules.nolink.exec(src))) { + || (cap = this.rules.nolink.exec(src))) { src = src.substring(cap[0].length); link = (cap[2] || cap[1]).replace(/\s+/g, ' '); link = this.links[link.toLowerCase()]; @@ -692,7 +694,7 @@ InlineLexer.prototype.output = function (src) { // code if (cap = this.rules.code.exec(src)) { src = src.substring(cap[0].length); - out += this.renderer.codespan(escape(cap[3].trim(), true)); + out += this.renderer.codespan(escape(cap[2].trim(), true)); continue; } @@ -718,8 +720,7 @@ InlineLexer.prototype.output = function (src) { } if (src) { - throw new - Error('Infinite loop on byte: ' + src.charCodeAt(0)); + throw new Error('Infinite loop on byte: ' + src.charCodeAt(0)); } } @@ -730,9 +731,9 @@ InlineLexer.prototype.output = function (src) { * Compile Link */ -InlineLexer.prototype.outputLink = function (cap, link) { - var href = escape(link.href) - , title = link.title ? escape(link.title) : null; +InlineLexer.prototype.outputLink = function(cap, link) { + var href = escape(link.href), + title = link.title ? escape(link.title) : null; return cap[0].charAt(0) !== '!' ? this.renderer.link(href, title, this.output(cap[1])) @@ -743,7 +744,7 @@ InlineLexer.prototype.outputLink = function (cap, link) { * Smartypants Transformations */ -InlineLexer.prototype.smartypants = function (text) { +InlineLexer.prototype.smartypants = function(text) { if (!this.options.smartypants) return text; return text // em-dashes @@ -766,12 +767,12 @@ InlineLexer.prototype.smartypants = function (text) { * Mangle Links */ -InlineLexer.prototype.mangle = function (text) { +InlineLexer.prototype.mangle = function(text) { if (!this.options.mangle) return text; - var out = '' - , l = text.length - , i = 0 - , ch; + var out = '', + l = text.length, + i = 0, + ch; for (; i < l; i++) { ch = text.charCodeAt(i); @@ -792,7 +793,7 @@ function Renderer(options) { this.options = options || {}; } -Renderer.prototype.code = function (code, lang, escaped) { +Renderer.prototype.code = function(code, lang, escaped) { if (this.options.highlight) { var out = this.options.highlight(code, lang); if (out != null && out !== code) { @@ -815,15 +816,15 @@ Renderer.prototype.code = function (code, lang, escaped) { + '\n\n'; }; -Renderer.prototype.blockquote = function (quote) { +Renderer.prototype.blockquote = function(quote) { return '
\n' + quote + '
\n'; }; -Renderer.prototype.html = function (html) { +Renderer.prototype.html = function(html) { return html; }; -Renderer.prototype.heading = function (text, level, raw) { +Renderer.prototype.heading = function(text, level, raw) { return '\n' + body + '\n'; }; -Renderer.prototype.listitem = function (text) { +Renderer.prototype.listitem = function(text) { return '
  • ' + text + '
  • \n'; }; -Renderer.prototype.paragraph = function (text) { +Renderer.prototype.paragraph = function(text) { return '

    ' + text + '

    \n'; }; -Renderer.prototype.table = function (header, body) { +Renderer.prototype.table = function(header, body) { return '\n' + '\n' + header @@ -864,11 +866,11 @@ Renderer.prototype.table = function (header, body) { + '
    \n'; }; -Renderer.prototype.tablerow = function (content) { +Renderer.prototype.tablerow = function(content) { return '\n' + content + '\n'; }; -Renderer.prototype.tablecell = function (content, flags) { +Renderer.prototype.tablecell = function(content, flags) { var type = flags.header ? 'th' : 'td'; var tag = flags.align ? '<' + type + ' style="text-align:' + flags.align + '">' @@ -877,27 +879,27 @@ Renderer.prototype.tablecell = function (content, flags) { }; // span level renderer -Renderer.prototype.strong = function (text) { +Renderer.prototype.strong = function(text) { return '' + text + ''; }; -Renderer.prototype.em = function (text) { +Renderer.prototype.em = function(text) { return '' + text + ''; }; -Renderer.prototype.codespan = function (text) { +Renderer.prototype.codespan = function(text) { return '' + text + ''; }; -Renderer.prototype.br = function () { +Renderer.prototype.br = function() { return this.options.xhtml ? '
    ' : '
    '; }; -Renderer.prototype.del = function (text) { +Renderer.prototype.del = function(text) { return '' + text + ''; }; -Renderer.prototype.link = function (href, title, text) { +Renderer.prototype.link = function(href, title, text) { if (this.options.sanitize) { try { var prot = decodeURIComponent(unescape(href)) @@ -921,7 +923,7 @@ Renderer.prototype.link = function (href, title, text) { return out; }; -Renderer.prototype.image = function (href, title, text) { +Renderer.prototype.image = function(href, title, text) { if (this.options.baseUrl && !originIndependentUrl.test(href)) { href = resolveUrl(this.options.baseUrl, href); } @@ -933,7 +935,7 @@ Renderer.prototype.image = function (href, title, text) { return out; }; -Renderer.prototype.text = function (text) { +Renderer.prototype.text = function(text) { return text; }; @@ -942,24 +944,24 @@ Renderer.prototype.text = function (text) { * returns only the textual part of the token */ -function TextRenderer() { } +function TextRenderer() {} // no need for block level renderers TextRenderer.prototype.strong = - TextRenderer.prototype.em = - TextRenderer.prototype.codespan = - TextRenderer.prototype.del = - TextRenderer.prototype.text = function (text) { - return text; - } +TextRenderer.prototype.em = +TextRenderer.prototype.codespan = +TextRenderer.prototype.del = +TextRenderer.prototype.text = function (text) { + return text; +} TextRenderer.prototype.link = - TextRenderer.prototype.image = function (href, title, text) { - return '' + text; - } +TextRenderer.prototype.image = function(href, title, text) { + return '' + text; +} -TextRenderer.prototype.br = function () { +TextRenderer.prototype.br = function() { return ''; } @@ -971,7 +973,7 @@ function Parser(options) { this.tokens = []; this.token = null; this.options = options || marked.defaults; - this.options.renderer = this.options.renderer || new Renderer; + this.options.renderer = this.options.renderer || new Renderer(); this.renderer = this.options.renderer; this.renderer.options = this.options; } @@ -980,7 +982,7 @@ function Parser(options) { * Static Parse Method */ -Parser.parse = function (src, options) { +Parser.parse = function(src, options) { var parser = new Parser(options); return parser.parse(src); }; @@ -989,10 +991,13 @@ Parser.parse = function (src, options) { * Parse Loop */ -Parser.prototype.parse = function (src) { +Parser.prototype.parse = function(src) { this.inline = new InlineLexer(src.links, this.options); // use an InlineLexer with a TextRenderer to extract pure text - this.inlineText = new InlineLexer(src.links, merge({}, this.options, { renderer: new TextRenderer })); + this.inlineText = new InlineLexer( + src.links, + merge({}, this.options, {renderer: new TextRenderer()}) + ); this.tokens = src.reverse(); var out = ''; @@ -1007,7 +1012,7 @@ Parser.prototype.parse = function (src) { * Next Token */ -Parser.prototype.next = function () { +Parser.prototype.next = function() { return this.token = this.tokens.pop(); }; @@ -1015,7 +1020,7 @@ Parser.prototype.next = function () { * Preview Next Token */ -Parser.prototype.peek = function () { +Parser.prototype.peek = function() { return this.tokens[this.tokens.length - 1] || 0; }; @@ -1023,7 +1028,7 @@ Parser.prototype.peek = function () { * Parse Text Tokens */ -Parser.prototype.parseText = function () { +Parser.prototype.parseText = function() { var body = this.token.text; while (this.peek().type === 'text') { @@ -1037,7 +1042,7 @@ Parser.prototype.parseText = function () { * Parse Current Token */ -Parser.prototype.tok = function () { +Parser.prototype.tok = function() { switch (this.token.type) { case 'space': { return ''; @@ -1057,12 +1062,12 @@ Parser.prototype.tok = function () { this.token.escaped); } case 'table': { - var header = '' - , body = '' - , i - , row - , cell - , j; + var header = '', + body = '', + i, + row, + cell, + j; // header cell = ''; @@ -1090,7 +1095,7 @@ Parser.prototype.tok = function () { return this.renderer.table(header, body); } case 'blockquote_start': { - var body = ''; + body = ''; while (this.next().type !== 'blockquote_end') { body += this.tok(); @@ -1099,17 +1104,18 @@ Parser.prototype.tok = function () { return this.renderer.blockquote(body); } case 'list_start': { - var body = '' - , ordered = this.token.ordered; + body = ''; + var ordered = this.token.ordered, + start = this.token.start; while (this.next().type !== 'list_end') { body += this.tok(); } - return this.renderer.list(body, ordered); + return this.renderer.list(body, ordered, start); } case 'list_item_start': { - var body = ''; + body = ''; while (this.next().type !== 'list_item_end') { body += this.token.type === 'text' @@ -1120,7 +1126,7 @@ Parser.prototype.tok = function () { return this.renderer.listitem(body); } case 'loose_item_start': { - var body = ''; + body = ''; while (this.next().type !== 'list_item_end') { body += this.tok(); @@ -1158,7 +1164,7 @@ function escape(html, encode) { function unescape(html) { // explicitly match decimal, hex, and named HTML entities - return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function (_, n) { + return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) { n = n.toLowerCase(); if (n === 'colon') return ':'; if (n.charAt(0) === '#') { @@ -1170,15 +1176,19 @@ function unescape(html) { }); } -function replace(regex, opt) { +function edit(regex, opt) { regex = regex.source; opt = opt || ''; - return function self(name, val) { - if (!name) return new RegExp(regex, opt); - val = val.source || val; - val = val.replace(/(^|[^\[])\^/g, '$1'); - regex = regex.replace(name, val); - return self; + return { + replace: function(name, val) { + val = val.source || val; + val = val.replace(/(^|[^\[])\^/g, '$1'); + regex = regex.replace(name, val); + return this; + }, + getRegex: function() { + return new RegExp(regex, opt); + } }; } @@ -1206,13 +1216,13 @@ function resolveUrl(base, href) { var baseUrls = {}; var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i; -function noop() { } +function noop() {} noop.exec = noop; function merge(obj) { - var i = 1 - , target - , key; + var i = 1, + target, + key; for (; i < arguments.length; i++) { target = arguments[i]; @@ -1226,19 +1236,19 @@ function merge(obj) { return obj; } - /** * Marked */ function marked(src, opt, callback) { // throw error in case of non string input - if (typeof src == 'undefined' || src === null) + if (typeof src === 'undefined' || src === null) { throw new Error('marked(): input parameter is undefined or null'); - if (typeof src != 'string') - throw new Error('marked(): input parameter is of type ' + - Object.prototype.toString.call(src) + ', string expected'); - + } + if (typeof src !== 'string') { + throw new Error('marked(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected'); + } if (callback || typeof opt === 'function') { if (!callback) { @@ -1248,10 +1258,10 @@ function marked(src, opt, callback) { opt = merge({}, marked.defaults, opt || {}); - var highlight = opt.highlight - , tokens - , pending - , i = 0; + var highlight = opt.highlight, + tokens, + pending, + i = 0; try { tokens = Lexer.lex(src, opt) @@ -1261,7 +1271,7 @@ function marked(src, opt, callback) { pending = tokens.length; - var done = function (err) { + var done = function(err) { if (err) { opt.highlight = highlight; return callback(err); @@ -1291,11 +1301,11 @@ function marked(src, opt, callback) { if (!pending) return done(); for (; i < tokens.length; i++) { - (function (token) { + (function(token) { if (token.type !== 'code') { return --pending || done(); } - return highlight(token.text, token.lang, function (err, code) { + return highlight(token.text, token.lang, function(err, code) { if (err) return done(err); if (code == null || code === token.text) { return --pending || done(); @@ -1313,7 +1323,7 @@ function marked(src, opt, callback) { if (opt) opt = merge({}, marked.defaults, opt); return Parser.parse(Lexer.lex(src, opt), opt); } catch (e) { - e.message += '\nPlease report this to https://github.com/chjj/marked.'; + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; if ((opt || marked.defaults).silent) { return '

    An error occurred:

    '
             + escape(e.message + '', true)
    @@ -1328,10 +1338,10 @@ function marked(src, opt, callback) {
      */
     
     marked.options =
    -  marked.setOptions = function (opt) {
    -    merge(marked.defaults, opt);
    -    return marked;
    -  };
    +marked.setOptions = function(opt) {
    +  merge(marked.defaults, opt);
    +  return marked;
    +};
     
     marked.defaults = {
       gfm: true,
    @@ -1347,7 +1357,7 @@ marked.defaults = {
       langPrefix: 'lang-',
       smartypants: false,
       headerPrefix: '',
    -  renderer: new Renderer,
    +  renderer: new Renderer(),
       xhtml: false,
       baseUrl: null
     };
    diff --git a/src/vs/base/common/marshalling.ts b/src/vs/base/common/marshalling.ts
    index 2c7acfe7d82..4d921569ba1 100644
    --- a/src/vs/base/common/marshalling.ts
    +++ b/src/vs/base/common/marshalling.ts
    @@ -16,7 +16,7 @@ export function parse(text: string): any {
     	return data;
     }
     
    -interface MarshalledObject {
    +export interface MarshalledObject {
     	$mid: number;
     }
     
    diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts
    index e0e8f7c05ae..70c4b3ae231 100644
    --- a/src/vs/base/common/paths.ts
    +++ b/src/vs/base/common/paths.ts
    @@ -5,7 +5,7 @@
     'use strict';
     
     import { isWindows } from 'vs/base/common/platform';
    -import { beginsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings';
    +import { startsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings';
     import { CharCode } from 'vs/base/common/charCode';
     
     /**
    @@ -340,7 +340,7 @@ export function isEqualOrParent(path: string, candidate: string, ignoreCase?: bo
     	}
     
     	if (ignoreCase) {
    -		const beginsWith = beginsWithIgnoreCase(path, candidate);
    +		const beginsWith = startsWithIgnoreCase(path, candidate);
     		if (!beginsWith) {
     			return false;
     		}
    diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts
    index f1eef60ca00..deeb3ae1f99 100644
    --- a/src/vs/base/common/strings.ts
    +++ b/src/vs/base/common/strings.ts
    @@ -159,6 +159,10 @@ export function startsWith(haystack: string, needle: string): boolean {
     		return false;
     	}
     
    +	if (haystack === needle) {
    +		return true;
    +	}
    +
     	for (let i = 0; i < needle.length; i++) {
     		if (haystack[i] !== needle[i]) {
     			return false;
    @@ -427,7 +431,7 @@ function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean {
     	return true;
     }
     
    -export function beginsWithIgnoreCase(str: string, candidate: string): boolean {
    +export function startsWithIgnoreCase(str: string, candidate: string): boolean {
     	const candidateLength = candidate.length;
     	if (candidate.length > str.length) {
     		return false;
    diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts
    index 0099aac4956..dc70fcab127 100644
    --- a/src/vs/base/common/worker/simpleWorker.ts
    +++ b/src/vs/base/common/worker/simpleWorker.ts
    @@ -116,7 +116,7 @@ class SimpleWorkerProtocol {
     		} catch (e) {
     			// nothing
     		}
    -		if (!message.vsWorker) {
    +		if (!message || !message.vsWorker) {
     			return;
     		}
     		if (this._workerId !== -1 && message.vsWorker !== this._workerId) {
    diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts
    index a827297f725..7e5ca3abaf8 100644
    --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts
    +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts
    @@ -7,9 +7,9 @@
     
     import { compareAnything } from 'vs/base/common/comparers';
     import { matchesPrefix, IMatch, createMatches, matchesCamelCase, isUpper } from 'vs/base/common/filters';
    -import { isEqual, nativeSep } from 'vs/base/common/paths';
    -import { isWindows } from 'vs/base/common/platform';
    -import { stripWildcards } from 'vs/base/common/strings';
    +import { nativeSep } from 'vs/base/common/paths';
    +import { isWindows, isLinux } from 'vs/base/common/platform';
    +import { stripWildcards, equalsIgnoreCase } from 'vs/base/common/strings';
     import { CharCode } from 'vs/base/common/charCode';
     
     export type Score = [number /* score */, number[] /* match positions */];
    @@ -356,7 +356,7 @@ export function scoreItem(item: T, query: IPreparedQuery, fuzzy: boolean, acc
     function doScoreItem(label: string, description: string, path: string, query: IPreparedQuery, fuzzy: boolean): IItemScore {
     
     	// 1.) treat identity matches on full path highest
    -	if (path && isEqual(query.original, path, true)) {
    +	if (path && isLinux ? query.original === path : equalsIgnoreCase(query.original, path)) {
     		return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : void 0 };
     	}
     
    diff --git a/src/vs/base/parts/tree/browser/treeImpl.ts b/src/vs/base/parts/tree/browser/treeImpl.ts
    index 42df25ee308..7821495d25d 100644
    --- a/src/vs/base/parts/tree/browser/treeImpl.ts
    +++ b/src/vs/base/parts/tree/browser/treeImpl.ts
    @@ -122,8 +122,8 @@ export class Tree implements _.ITree {
     		return this.view.getHTMLElement();
     	}
     
    -	public layout(height?: number): void {
    -		this.view.layout(height);
    +	public layout(height?: number, width?: number): void {
    +		this.view.layout(height, width);
     	}
     
     	public domFocus(): void {
    diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts
    index 024564b7faa..91e59737d7c 100644
    --- a/src/vs/base/parts/tree/browser/treeView.ts
    +++ b/src/vs/base/parts/tree/browser/treeView.ts
    @@ -636,7 +636,7 @@ export class TreeView extends HeightMap {
     		return this.onHiddenScrollTop === null;
     	}
     
    -	public layout(height?: number): void {
    +	public layout(height?: number, width?: number): void {
     		if (!this.isTreeVisible()) {
     			return;
     		}
    @@ -645,7 +645,7 @@ export class TreeView extends HeightMap {
     		this.scrollHeight = this.getContentHeight();
     
     		if (this.horizontalScrolling) {
    -			this.viewWidth = DOM.getContentWidth(this.wrapper);
    +			this.viewWidth = width || DOM.getContentWidth(this.wrapper);
     		}
     	}
     
    @@ -1675,6 +1675,11 @@ export class TreeView extends HeightMap {
     		}
     		this.domNode = null;
     
    +		if (this.items) {
    +			Object.keys(this.items).forEach(key => this.items[key].removeFromDOM());
    +			this.items = null;
    +		}
    +
     		if (this.context.cache) {
     			this.context.cache.dispose();
     			this.context.cache = null;
    diff --git a/src/vs/base/test/common/cancellation.test.ts b/src/vs/base/test/common/cancellation.test.ts
    index ba67e474ef1..e2f1a1f5e0c 100644
    --- a/src/vs/base/test/common/cancellation.test.ts
    +++ b/src/vs/base/test/common/cancellation.test.ts
    @@ -82,4 +82,18 @@ suite('CancellationToken', function () {
     		token = source.token;
     		assert.ok(token === source.token); // doesn't change on get
     	});
    +
    +	test('dispose calls no listeners', function () {
    +
    +		let count = 0;
    +
    +		let source = new CancellationTokenSource();
    +		source.token.onCancellationRequested(function () {
    +			count += 1;
    +		});
    +
    +		source.dispose();
    +		source.cancel();
    +		assert.equal(count, 0);
    +	});
     });
    diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts
    index 748b6ea5138..2ef6786f9ae 100644
    --- a/src/vs/base/test/common/event.test.ts
    +++ b/src/vs/base/test/common/event.test.ts
    @@ -5,7 +5,7 @@
     'use strict';
     
     import * as assert from 'assert';
    -import { Event, Emitter, debounceEvent, EventBufferer, once, fromPromise, stopwatch, buffer, echo, EventMultiplexer } from 'vs/base/common/event';
    +import { Event, Emitter, debounceEvent, EventBufferer, once, fromPromise, stopwatch, buffer, echo, EventMultiplexer, latch } from 'vs/base/common/event';
     import { IDisposable } from 'vs/base/common/lifecycle';
     import * as Errors from 'vs/base/common/errors';
     import { TPromise } from 'vs/base/common/winjs.base';
    @@ -651,4 +651,40 @@ suite('Event utils', () => {
     			assert.deepEqual(result, [1, 2, 3, 4, 5]);
     		});
     	});
    +
    +	test('latch', function () {
    +		const emitter = new Emitter();
    +		const event = latch(emitter.event);
    +
    +		const result: number[] = [];
    +		const listener = event(num => result.push(num));
    +
    +		assert.deepEqual(result, []);
    +
    +		emitter.fire(1);
    +		assert.deepEqual(result, [1]);
    +
    +		emitter.fire(2);
    +		assert.deepEqual(result, [1, 2]);
    +
    +		emitter.fire(2);
    +		assert.deepEqual(result, [1, 2]);
    +
    +		emitter.fire(1);
    +		assert.deepEqual(result, [1, 2, 1]);
    +
    +		emitter.fire(1);
    +		assert.deepEqual(result, [1, 2, 1]);
    +
    +		emitter.fire(3);
    +		assert.deepEqual(result, [1, 2, 1, 3]);
    +
    +		emitter.fire(3);
    +		assert.deepEqual(result, [1, 2, 1, 3]);
    +
    +		emitter.fire(3);
    +		assert.deepEqual(result, [1, 2, 1, 3]);
    +
    +		listener.dispose();
    +	});
     });
    diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts
    index 4db726aae72..295c3adb50a 100644
    --- a/src/vs/base/test/common/strings.test.ts
    +++ b/src/vs/base/test/common/strings.test.ts
    @@ -21,29 +21,29 @@ suite('Strings', () => {
     	});
     
     	test('beginsWithIgnoreCase', function () {
    -		assert(strings.beginsWithIgnoreCase('', ''));
    -		assert(!strings.beginsWithIgnoreCase('', '1'));
    -		assert(strings.beginsWithIgnoreCase('1', ''));
    +		assert(strings.startsWithIgnoreCase('', ''));
    +		assert(!strings.startsWithIgnoreCase('', '1'));
    +		assert(strings.startsWithIgnoreCase('1', ''));
     
    -		assert(strings.beginsWithIgnoreCase('a', 'a'));
    -		assert(strings.beginsWithIgnoreCase('abc', 'Abc'));
    -		assert(strings.beginsWithIgnoreCase('abc', 'ABC'));
    -		assert(strings.beginsWithIgnoreCase('Höhenmeter', 'HÖhenmeter'));
    -		assert(strings.beginsWithIgnoreCase('ÖL', 'Öl'));
    +		assert(strings.startsWithIgnoreCase('a', 'a'));
    +		assert(strings.startsWithIgnoreCase('abc', 'Abc'));
    +		assert(strings.startsWithIgnoreCase('abc', 'ABC'));
    +		assert(strings.startsWithIgnoreCase('Höhenmeter', 'HÖhenmeter'));
    +		assert(strings.startsWithIgnoreCase('ÖL', 'Öl'));
     
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'a'));
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'A'));
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'alles k'));
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'alles K'));
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'ALLES K'));
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'alles klar'));
    -		assert(strings.beginsWithIgnoreCase('alles klar', 'ALLES KLAR'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'a'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'A'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'alles k'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'alles K'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'ALLES K'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'alles klar'));
    +		assert(strings.startsWithIgnoreCase('alles klar', 'ALLES KLAR'));
     
    -		assert(!strings.beginsWithIgnoreCase('alles klar', ' ALLES K'));
    -		assert(!strings.beginsWithIgnoreCase('alles klar', 'ALLES K '));
    -		assert(!strings.beginsWithIgnoreCase('alles klar', 'öALLES K '));
    -		assert(!strings.beginsWithIgnoreCase('alles klar', ' '));
    -		assert(!strings.beginsWithIgnoreCase('alles klar', 'ö'));
    +		assert(!strings.startsWithIgnoreCase('alles klar', ' ALLES K'));
    +		assert(!strings.startsWithIgnoreCase('alles klar', 'ALLES K '));
    +		assert(!strings.startsWithIgnoreCase('alles klar', 'öALLES K '));
    +		assert(!strings.startsWithIgnoreCase('alles klar', ' '));
    +		assert(!strings.startsWithIgnoreCase('alles klar', 'ö'));
     	});
     
     	test('compareIgnoreCase', function () {
    diff --git a/src/vs/base/worker/defaultWorkerFactory.ts b/src/vs/base/worker/defaultWorkerFactory.ts
    index 344588ad9ef..4fe3caa2403 100644
    --- a/src/vs/base/worker/defaultWorkerFactory.ts
    +++ b/src/vs/base/worker/defaultWorkerFactory.ts
    @@ -7,17 +7,22 @@
     import { globals } from 'vs/base/common/platform';
     import { logOnceWebWorkerWarning, IWorker, IWorkerCallback, IWorkerFactory } from 'vs/base/common/worker/simpleWorker';
     
    -function getWorkerUrl(workerId: string, label: string): string {
    -	// Option for hosts to overwrite the worker script url (used in the standalone editor)
    -	if (globals.MonacoEnvironment && typeof globals.MonacoEnvironment.getWorkerUrl === 'function') {
    -		return globals.MonacoEnvironment.getWorkerUrl(workerId, label);
    +function getWorker(workerId: string, label: string): Worker {
    +	// Option for hosts to overwrite the worker script (used in the standalone editor)
    +	if (globals.MonacoEnvironment) {
    +		if (typeof globals.MonacoEnvironment.getWorker === 'function') {
    +			return globals.MonacoEnvironment.getWorker(workerId, label);
    +		}
    +		if (typeof globals.MonacoEnvironment.getWorkerUrl === 'function') {
    +			return new Worker(globals.MonacoEnvironment.getWorkerUrl(workerId, label));
    +		}
     	}
     	// ESM-comment-begin
     	if (typeof require === 'function') {
    -		return require.toUrl('./' + workerId) + '#' + label;
    +		return new Worker(require.toUrl('./' + workerId) + '#' + label);
     	}
     	// ESM-comment-end
    -	throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl`);
    +	throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);
     }
     
     /**
    @@ -31,7 +36,7 @@ class WebWorker implements IWorker {
     
     	constructor(moduleId: string, id: number, label: string, onMessageCallback: IWorkerCallback, onErrorCallback: (err: any) => void) {
     		this.id = id;
    -		this.worker = new Worker(getWorkerUrl('workerMain.js', label));
    +		this.worker = getWorker('workerMain.js', label);
     		this.postMessage(moduleId);
     		this.worker.onmessage = function (ev: any) {
     			onMessageCallback(ev.data);
    diff --git a/src/vs/code/electron-browser/issue/issueReporter.js b/src/vs/code/electron-browser/issue/issueReporter.js
    index 01d097357b0..423dbe75a1c 100644
    --- a/src/vs/code/electron-browser/issue/issueReporter.js
    +++ b/src/vs/code/electron-browser/issue/issueReporter.js
    @@ -19,15 +19,6 @@ function parseURLQueryArgs() {
     		.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
     }
     
    -function createScript(src, onload) {
    -	const script = document.createElement('script');
    -	script.src = src;
    -	script.addEventListener('load', onload);
    -
    -	const head = document.getElementsByTagName('head')[0];
    -	head.insertBefore(script, head.lastChild);
    -}
    -
     function uriFromPath(_path) {
     	var pathName = path.resolve(_path).replace(/\\/g, '/');
     	if (pathName.length > 0 && pathName.charAt(0) !== '/') {
    @@ -65,10 +56,10 @@ function main() {
     		const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar';
     
     		const originalResolveLookupPaths = Module._resolveLookupPaths;
    -		Module._resolveLookupPaths = function (request, parent) {
    -			const result = originalResolveLookupPaths(request, parent);
    +		Module._resolveLookupPaths = function (request, parent, newReturn) {
    +			const result = originalResolveLookupPaths(request, parent, newReturn);
     
    -			const paths = result[1];
    +			const paths = newReturn ? result : result[1];
     			for (let i = 0, len = paths.length; i < len; i++) {
     				if (paths[i] === NODE_MODULES_PATH) {
     					paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
    @@ -143,31 +134,34 @@ function main() {
     
     	window.document.documentElement.setAttribute('lang', locale);
     
    -	// In the bundled version the nls plugin is packaged with the loader so the NLS Plugins
    -	// loads as soon as the loader loads. To be able to have pseudo translation
    -	createScript(rootUrl + '/vs/loader.js', function () {
    -		var define = global.define;
    -		global.define = undefined;
    -		define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
    +	// Load the loader
    +	const loaderFilename = configuration.appRoot + '/out/vs/loader.js';
    +	const loaderSource = fs.readFileSync(loaderFilename);
    +	require('vm').runInThisContext(loaderSource, { filename: loaderFilename });
    +	var define = global.define;
    +	global.define = undefined;
     
    -		window.MonacoEnvironment = {};
    +	window.nodeRequire = require.__$__nodeRequire;
     
    -		require.config({
    -			baseUrl: rootUrl,
    -			'vs/nls': nlsConfig,
    -			nodeCachedDataDir: configuration.nodeCachedDataDir,
    -			nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
    +	define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
    +
    +	window.MonacoEnvironment = {};
    +
    +	require.config({
    +		baseUrl: rootUrl,
    +		'vs/nls': nlsConfig,
    +		nodeCachedDataDir: configuration.nodeCachedDataDir,
    +		nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
    +	});
    +
    +	if (nlsConfig.pseudo) {
    +		require(['vs/nls'], function (nlsPlugin) {
    +			nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
     		});
    +	}
     
    -		if (nlsConfig.pseudo) {
    -			require(['vs/nls'], function (nlsPlugin) {
    -				nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
    -			});
    -		}
    -
    -		require(['vs/code/electron-browser/issue/issueReporterMain'], (issueReporter) => {
    -			issueReporter.startup(configuration);
    -		});
    +	require(['vs/code/electron-browser/issue/issueReporterMain'], (issueReporter) => {
    +		issueReporter.startup(configuration);
     	});
     }
     
    diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts
    index f6bbf228784..78aa4c56373 100644
    --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts
    +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts
    @@ -40,6 +40,7 @@ import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
     import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
     import { ILogService, getLogLevel } from 'vs/platform/log/common/log';
     import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
    +import { normalizeGitHubIssuesUrl } from 'vs/code/electron-browser/issue/issueReporterUtil';
     
     const MAX_URL_LENGTH = platform.isWindows ? 2081 : 5400;
     
    @@ -69,6 +70,7 @@ export class IssueReporter extends Disposable {
     	private numberOfSearchResultsDisplayed = 0;
     	private receivedSystemInfo = false;
     	private receivedPerformanceInfo = false;
    +	private shouldQueueSearch = false;
     
     	constructor(configuration: IssueReporterConfiguration) {
     		super();
    @@ -208,14 +210,14 @@ export class IssueReporter extends Disposable {
     		});
     
     		const numberOfThemeExtesions = themes && themes.length;
    -		this.issueReporterModel.update({ numberOfThemeExtesions, enabledNonThemeExtesions: nonThemes });
    +		this.issueReporterModel.update({ numberOfThemeExtesions, enabledNonThemeExtesions: nonThemes, allExtensions: extensions });
     		this.updateExtensionTable(nonThemes, numberOfThemeExtesions);
     
     		if (this.environmentService.disableExtensions || extensions.length === 0) {
     			(document.getElementById('disableExtensions')).disabled = true;
    -			(document.getElementById('reproducesWithoutExtensions')).checked = true;
    -			this.issueReporterModel.update({ reprosWithoutExtensions: true });
     		}
    +
    +		this.updateExtensionSelector(extensions);
     	}
     
     	private handleSettingsSearchData(data: ISettingsSearchIssueReporterData): void {
    @@ -322,30 +324,34 @@ export class IssueReporter extends Disposable {
     			});
     		}
     
    -		this.addEventListener('reproducesWithoutExtensions', 'click', (e) => {
    -			this.issueReporterModel.update({ reprosWithoutExtensions: true });
    -		});
    +		this.addEventListener('issue-source', 'change', (event: Event) => {
    +			const fileOnExtension = JSON.parse((event.target).value);
    +			this.issueReporterModel.update({ fileOnExtension: fileOnExtension, includeExtensions: !fileOnExtension, selectedExtension: null });
    +			this.render();
     
    -		this.addEventListener('reproducesWithExtensions', 'click', (e) => {
    -			this.issueReporterModel.update({ reprosWithoutExtensions: false });
    +			const title = (document.getElementById('issue-title')).value;
    +			if (fileOnExtension) {
    +				this.searchExtensionIssues(title);
    +			} else {
    +				const description = this.issueReporterModel.getData().issueDescription;
    +				this.searchVSCodeIssues(title, description);
    +			}
     		});
     
     		this.addEventListener('description', 'input', (event: Event) => {
     			const issueDescription = (event.target).value;
     			this.issueReporterModel.update({ issueDescription });
     
    -			const title = (document.getElementById('issue-title')).value;
    -			if (title || issueDescription) {
    -				this.searchDuplicates(title, issueDescription);
    -			} else {
    -				this.clearSearchResults();
    +			// Only search for extension issues on title change
    +			const fileOnExtension = this.issueReporterModel.getData().fileOnExtension;
    +			if (!fileOnExtension) {
    +				const title = (document.getElementById('issue-title')).value;
    +				this.searchVSCodeIssues(title, issueDescription);
     			}
     		});
     
     		this.addEventListener('issue-title', 'input', (e) => {
    -			const description = this.issueReporterModel.getData().issueDescription;
     			const title = (event.target).value;
    -
     			const lengthValidationMessage = document.getElementById('issue-title-length-validation-error');
     			if (title && this.getIssueUrlWithTitle(title).length > MAX_URL_LENGTH) {
     				show(lengthValidationMessage);
    @@ -353,10 +359,12 @@ export class IssueReporter extends Disposable {
     				hide(lengthValidationMessage);
     			}
     
    -			if (title || description) {
    -				this.searchDuplicates(title, description);
    +			const fileOnExtension = this.issueReporterModel.getData().fileOnExtension;
    +			if (fileOnExtension) {
    +				this.searchExtensionIssues(title);
     			} else {
    -				this.clearSearchResults();
    +				const description = this.issueReporterModel.getData().issueDescription;
    +				this.searchVSCodeIssues(title, description);
     			}
     		});
     
    @@ -373,16 +381,6 @@ export class IssueReporter extends Disposable {
     			}
     		});
     
    -		this.addEventListener('showRunning', 'click', () => {
    -			ipcRenderer.send('workbenchCommand', 'workbench.action.showRuntimeExtensions');
    -		});
    -
    -		this.addEventListener('showRunning', 'keydown', (e: KeyboardEvent) => {
    -			if (e.keyCode === 13 || e.keyCode === 32) {
    -				ipcRenderer.send('workbenchCommand', 'workbench.action.showRuntimeExtensions');
    -			}
    -		});
    -
     		// Cmd+Enter or Mac or Ctrl+Enter on other platforms previews issue and closes window
     		if (platform.isMacintosh) {
     			let prevKeyWasCommand = false;
    @@ -438,12 +436,77 @@ export class IssueReporter extends Disposable {
     		return false;
     	}
     
    +	private getExtensionRepositoryUrl(): string {
    +		const selectedExtension = this.issueReporterModel.getData().selectedExtension;
    +		return selectedExtension && selectedExtension.manifest && selectedExtension.manifest.repository && selectedExtension.manifest.repository.url;
    +	}
    +
    +	private getExtensionBugsUrl(): string {
    +		const selectedExtension = this.issueReporterModel.getData().selectedExtension;
    +		return selectedExtension && selectedExtension.manifest && selectedExtension.manifest.bugs && selectedExtension.manifest.bugs.url;
    +	}
    +
    +	private searchVSCodeIssues(title: string, issueDescription: string): void {
    +		if (title || issueDescription) {
    +			this.searchDuplicates(title, issueDescription);
    +		} else {
    +			this.clearSearchResults();
    +		}
    +	}
    +
    +	private searchExtensionIssues(title: string): void {
    +		const url = this.getExtensionRepositoryUrl();
    +		if (title) {
    +			const matches = /^https?:\/\/github\.com\/(.*)(?:.git)/.exec(url);
    +			if (matches && matches.length) {
    +				const repo = matches[1];
    +				return this.searchGitHub(repo, title);
    +			}
    +		}
    +
    +		this.clearSearchResults();
    +	}
    +
     	private clearSearchResults(): void {
     		const similarIssues = document.getElementById('similar-issues');
     		similarIssues.innerHTML = '';
     		this.numberOfSearchResultsDisplayed = 0;
     	}
     
    +	@debounce(300)
    +	private searchGitHub(repo: string, title: string): void {
    +		const query = `is:issue+repo:${repo}+${title}`;
    +		const similarIssues = document.getElementById('similar-issues');
    +
    +		window.fetch(`https://api.github.com/search/issues?q=${query}`).then((response) => {
    +			response.json().then(result => {
    +				similarIssues.innerHTML = '';
    +				if (result && result.items) {
    +					this.displaySearchResults(result.items);
    +				} else {
    +					// If the items property isn't present, the rate limit has been hit
    +					const message = $('div.list-title');
    +					message.textContent = localize('rateLimited', "GitHub query limit exceeded. Please wait.");
    +					similarIssues.appendChild(message);
    +
    +					const resetTime = response.headers.get('X-RateLimit-Reset');
    +					const timeToWait = parseInt(resetTime) - Math.floor(Date.now() / 1000);
    +					if (this.shouldQueueSearch) {
    +						this.shouldQueueSearch = false;
    +						setTimeout(() => {
    +							this.searchGitHub(repo, title);
    +							this.shouldQueueSearch = true;
    +						}, timeToWait * 1000);
    +					}
    +				}
    +			}).catch(e => {
    +				this.logSearchError(e);
    +			});
    +		}).catch(e => {
    +			this.logSearchError(e);
    +		});
    +	}
    +
     	@debounce(300)
     	private searchDuplicates(title: string, body: string): void {
     		const url = 'https://vscode-probot.westus.cloudapp.azure.com:7890/duplicate_candidates';
    @@ -551,7 +614,7 @@ export class IssueReporter extends Disposable {
     
     	private renderBlocks(): void {
     		// Depending on Issue Type, we render different blocks and text
    -		const { issueType } = this.issueReporterModel.getData();
    +		const { issueType, fileOnExtension } = this.issueReporterModel.getData();
     		const blockContainer = document.getElementById('block-container');
     		const systemBlock = document.querySelector('.block-system');
     		const processBlock = document.querySelector('.block-process');
    @@ -560,9 +623,10 @@ export class IssueReporter extends Disposable {
     		const searchedExtensionsBlock = document.querySelector('.block-searchedExtensions');
     		const settingsSearchResultsBlock = document.querySelector('.block-settingsSearchResults');
     
    -		const disabledExtensions = document.getElementById('disabledExtensions');
    +		const problemSource = document.getElementById('problem-source');
     		const descriptionTitle = document.getElementById('issue-description-label');
     		const descriptionSubtitle = document.getElementById('issue-description-subtitle');
    +		const extensionSelector = document.getElementById('extension-selection');
     
     		// Hide all by default
     		hide(blockContainer);
    @@ -572,13 +636,20 @@ export class IssueReporter extends Disposable {
     		hide(extensionsBlock);
     		hide(searchedExtensionsBlock);
     		hide(settingsSearchResultsBlock);
    -		hide(disabledExtensions);
    +		hide(problemSource);
     
     		if (issueType === IssueType.Bug) {
     			show(blockContainer);
     			show(systemBlock);
    -			show(extensionsBlock);
    -			show(disabledExtensions);
    +			show(problemSource);
    +
    +			if (fileOnExtension) {
    +				hide(extensionsBlock);
    +				show(extensionSelector);
    +			} else {
    +				show(extensionsBlock);
    +				hide(extensionSelector);
    +			}
     
     			descriptionTitle.innerHTML = `${localize('stepsToReproduce', "Steps to Reproduce")} *`;
     			descriptionSubtitle.innerHTML = localize('bugDescription', "Share the steps needed to reliably reproduce the problem. Please include actual and expected results. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.");
    @@ -588,7 +659,15 @@ export class IssueReporter extends Disposable {
     			show(processBlock);
     			show(workspaceBlock);
     			show(extensionsBlock);
    -			show(disabledExtensions);
    +			show(problemSource);
    +
    +			if (fileOnExtension) {
    +				hide(extensionsBlock);
    +				show(extensionSelector);
    +			} else {
    +				show(extensionsBlock);
    +				hide(extensionSelector);
    +			}
     
     			descriptionTitle.innerHTML = `${localize('stepsToReproduce', "Steps to Reproduce")} *`;
     			descriptionSubtitle.innerHTML = localize('performanceIssueDesciption', "When did this performance issue happen? Does it occur on startup or after a specific series of actions? We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.");
    @@ -618,11 +697,14 @@ export class IssueReporter extends Disposable {
     
     	private validateInputs(): boolean {
     		let isValid = true;
    -		['issue-title', 'description'].forEach(elementId => {
    +		['issue-title', 'description', 'issue-source'].forEach(elementId => {
     			isValid = this.validateInput(elementId) && isValid;
    -
     		});
     
    +		if (this.issueReporterModel.getData().fileOnExtension) {
    +			isValid = this.validateInput('extension-selector') && isValid;
    +		}
    +
     		return isValid;
     	}
     
    @@ -630,7 +712,10 @@ export class IssueReporter extends Disposable {
     		if (!this.validateInputs()) {
     			// If inputs are invalid, set focus to the first one and add listeners on them
     			// to detect further changes
    -			(document.getElementsByClassName('invalid-input')[0]).focus();
    +			const invalidInput = document.getElementsByClassName('invalid-input');
    +			if (invalidInput.length) {
    +				(invalidInput[0]).focus();
    +			}
     
     			document.getElementById('issue-title').addEventListener('input', (event) => {
     				this.validateInput('issue-title');
    @@ -664,9 +749,21 @@ export class IssueReporter extends Disposable {
     		return true;
     	}
     
    -	private getIssueUrlWithTitle(issueTitle: string) {
    +	private getIssueUrlWithTitle(issueTitle: string): string {
    +		let repositoryUrl = product.reportIssueUrl;
    +		if (this.issueReporterModel.getData().fileOnExtension) {
    +			const bugsUrl = this.getExtensionBugsUrl();
    +			const extensionUrl = this.getExtensionRepositoryUrl();
    +			// If given, try to match the extension's bug url
    +			if (bugsUrl && bugsUrl.match(/^https?:\/\/github\.com\/(.*)/)) {
    +				repositoryUrl = normalizeGitHubIssuesUrl(bugsUrl);
    +			} else if (extensionUrl && extensionUrl.match(/^https?:\/\/github\.com\/(.*)/)) {
    +				repositoryUrl = normalizeGitHubIssuesUrl(extensionUrl);
    +			}
    +		}
    +
     		const queryStringPrefix = product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
    -		return `${product.reportIssueUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
    +		return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
     	}
     
     	private updateSystemInfo = (state) => {
    @@ -682,6 +779,27 @@ export class IssueReporter extends Disposable {
     		target.innerHTML = `${tableHtml}
    `; } + private updateExtensionSelector(extensions: ILocalExtension[]): void { + const makeOption = (extension: ILocalExtension) => ``; + const extensionsSelector = document.getElementById('extension-selector'); + extensionsSelector.innerHTML = '' + extensions.map(makeOption).join('\n'); + + this.addEventListener('extension-selector', 'change', (e: Event) => { + const selectedExtensionId = (e.target).value; + const extensions = this.issueReporterModel.getData().allExtensions; + const matches = extensions.filter(extension => extension.identifier.id === selectedExtensionId); + if (matches.length) { + this.issueReporterModel.update({ selectedExtension: matches[0] }); + + const title = (document.getElementById('issue-title')).value; + this.searchExtensionIssues(title); + } else { + this.issueReporterModel.update({ selectedExtension: null }); + this.clearSearchResults(); + } + }); + } + private updateProcessInfo = (state) => { const target = document.querySelector('.block-process .block-info'); target.innerHTML = `${state.processInfo}`; diff --git a/src/vs/code/electron-browser/issue/issueReporterModel.ts b/src/vs/code/electron-browser/issue/issueReporterModel.ts index a6ec8153424..43d581ea6a3 100644 --- a/src/vs/code/electron-browser/issue/issueReporterModel.ts +++ b/src/vs/code/electron-browser/issue/issueReporterModel.ts @@ -26,9 +26,11 @@ export interface IssueReporterData { includeSettingsSearchDetails?: boolean; numberOfThemeExtesions?: number; + allExtensions?: ILocalExtension[]; enabledNonThemeExtesions?: ILocalExtension[]; extensionsDisabled?: boolean; - reprosWithoutExtensions?: boolean; + fileOnExtension?: boolean; + selectedExtension?: ILocalExtension; actualSearchResults?: ISettingSearchResult[]; query?: string; filterResultCount?: number; @@ -44,8 +46,7 @@ export class IssueReporterModel { includeProcessInfo: true, includeExtensions: true, includeSearchedExtensions: true, - includeSettingsSearchDetails: true, - reprosWithoutExtensions: false + includeSettingsSearchDetails: true }; this._data = initialData ? assign(defaultData, initialData) : defaultData; @@ -64,7 +65,7 @@ export class IssueReporterModel { Issue Type: ${this.getIssueTypeTitle()} ${this._data.issueDescription} - +${this.getExtensionVersion()} VS Code version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion} OS version: ${this._data.versionInfo && this._data.versionInfo.os} @@ -72,6 +73,14 @@ ${this.getInfos()} `; } + private getExtensionVersion(): string { + if (this._data.fileOnExtension) { + return `\nExtension version: ${this._data.selectedExtension.manifest.version}`; + } else { + return ''; + } + } + private getIssueTypeTitle(): string { if (this._data.issueType === IssueType.Bug) { return 'Bug'; @@ -108,8 +117,6 @@ ${this.getInfos()} if (this._data.includeExtensions) { info += this.generateExtensionsMd(); } - - info += this._data.reprosWithoutExtensions ? '\nReproduces without extensions' : '\nReproduces only with extensions'; } if (this._data.issueType === IssueType.SettingsSearchIssue) { diff --git a/src/vs/code/electron-browser/issue/issueReporterPage.ts b/src/vs/code/electron-browser/issue/issueReporterPage.ts index abf3c7b4ad6..045a35fb717 100644 --- a/src/vs/code/electron-browser/issue/issueReporterPage.ts +++ b/src/vs/code/electron-browser/issue/issueReporterPage.ts @@ -27,6 +27,25 @@ export default (): string => `
    + +
    + + +
    ${escape(localize('disableExtensionsLabelText', "Try to reproduce the problem after {0}. If the problem only reproduces when extensions are active, it is likely an issue with an extension.")) + .replace('{0}', `${escape(localize('disableExtensions', "disabling all extensions and reloading the window"))}`)} +
    + +
    + + +
    +
    +
    @@ -112,28 +131,6 @@ export default (): string => `
    -
    -
    - -
    -
    - - -
    -
    - - -
    -
    -
    -
    ${escape(localize('disableExtensionsLabelText', "Try to reproduce the problem after {0}.")) - .replace('{0}', `${escape(localize('disableExtensions', "disabling all extensions and reloading the window"))}`)} -
    -
    ${escape(localize('showRunningExtensionsLabelText', "If you suspect it's an extension issue, {0} to report the issue on the extension.")) - .replace('{0}', `${escape(localize('showRunningExtensions', "view all running extensions"))}`)} -
    -
    -